'encoding' and iconv

OpenWin32Explorer.vim ( http://d.hatena.ne.jp/janus_wel/20090307/1236442540 ) との絡みで。

おれは 'encoding' を utf-8 にしてるんだけどこうすると cmd.exe 経由での command で、つまり外部 command 全般で日本語がまともに通らない ( あーでもこれ Windows XP までの現象なのかな ? Vista とかいじったことないからわかんないな ) 。で、これをどうやって通すかというアレで。

おれが至った結論は cmd.exe に渡す文字列をあらかじめ iconv で system default の encoding に直してやる、ってことなんだけどこれだと 2 つの前提条件がいるんだよね。

  1. iconv support
    • vim で character encoding を変換するには iconv らしい。まぁ UNIX / Linux 発祥の文化だからこれが自然なのかもしれんけど Windows だともちろん iconv とか out of choice というか自力でいれることのない software のひとつなわけなんだけど ( 変換なんかは editor の機能に任せた方が手っ取り早い ) 。
    • でも Kaoriya さんとこの gvim は普通に support しているのでたぶん日本国内ではこの点は大丈夫。
    • 一応、 iconv support しているかは :echo has('iconv') で調べられる。
  2. cmd.exe が受け付ける encoding がわかっている
    • 日本語だとわかっているなら cp932 決めうちでほとんど大丈夫なんだけどそれもどうよと思ったので多言語で使えるような方法を考えてみた結果浮かんできたのは 2 つ。
    • ひとつめは encoding を指定してもらう。これはある意味確実なんだけどある意味不確実なので却下。
    • ふたつめの手段は 'encoding' option の default 値に期待する。 :help 'encoding' や :help encoding-values してみるとなんか大丈夫ぽい… ? のでこっちを採用。 maintainer はたぶん各言語ごとに適切な encoding を default にしてくれているはずだという淡い期待も正直入ってます。

で、ここらへんを考慮して system default の encoding に直す関数を以下のように書いてみた。必要になるまで iconv を呼ばない作りにしてるけど前提にしてしまったほうがいいかなぁ ? とりあえず意図通りに動いてくれているようなんだけど try, catch, throw が vim にもあって驚いたとか vim でこういう library につっこんでおくべき関数の扱いはどうするのが正しいんだろうとちょっと考えてみたりとかそもそも library って概念があるのかと迷ってしまったりした。

throw のタイミングで 'encoding' が default に戻ったままになるという bug があったのでちょっと変えたよ !! またまた thinca さんありがとう。

function! ConvertEncodingToSystemDefault(orig_str)
    let str = a:orig_str

    if has('multi_byte')
        " If 'encoding' option differ from system encoding, this
        " function needs iconv. In Windows, needs +iconv/dyn and
        " iconv.dll (libiconv.dll). See :help iconv-dynamic

        " error flag
        let error = 0

        " save 'encoding' to variable
        let cur_encoding = &encoding
        " get default 'encoding'
        set encoding&

        " check
        if cur_encoding != &encoding
            " try to convert
            if has('iconv')
                let str = iconv(str, cur_encoding, &encoding)
            else
                let error = 1
            endif
        endif

        " restore 'encoding'
        let &encoding = cur_encoding

        if error
            throw 'Feature +iconv is needed.'
                        \ . ' See :help iconv-dynamic.'
        endif
    endif

    return str
endfunction