vimをバイナリエディタ的に使う。
vimがいい、vimがいいを言い続けて4年目。
元はといえば学校のMacのemacsがやたら異常終了して、嫌気が差してvimを使い始めたのがハジマリ。
それまではWinユーザでメモ帳++なんぞを使っていたのですが...。
もしあのとき、emacsが異常終了しなければ、今頃自分は...。
そんなこんなで月日は流れ今となってはvim!vim!vim!な毎日。
暇さえあれば他人に布教し始める程のvim信者。
すべてのエディタはvim互換モードを持つべきだと言い張る今日この頃。
そういやバイナリエディタもvim互換がいいな。
いや、いっそvimがいい!
素敵そうではないか、vimでバイナリエディタ。
矩形選択がおもしろい程に活躍しそうだ。
正規表現による:sやら、マクロにC-A/C-X。
えっと、最初に一言だけ。
このエントリのまとめ: "vimで:help xxd"
備忘録ここまで。以下メモ程度に。
vimがインストールされている環境には必ず入っている(はず)のxxdというコマンド。
manを見てみると"make a hexdump or do the reverse"と書かれている。
何処を取ってxxdなのかは知らないが、eX-なんとか heX Dumpかなんかだろう。
16進数にdumpしたりその逆をするコマンドらしい。
vimと一緒にインストールされるので、多分大体のOSで何もせずに使えるはず。
で、vimのhelpにはこのxxdをフィルタとして使う方法が書いてある。
先に書いた":help xxd"で読めるのだが、
" vim -b : edit binary using xxd-format! augroup Binary au! au BufReadPre *.bin let &bin=1 au BufReadPost *.bin if &bin | %!xxd au BufReadPost *.bin set ft=xxd | endif au BufWritePre *.bin if &bin | %!xxd -r au BufWritePre *.bin endif au BufWritePost *.bin if &bin | %!xxd au BufWritePost *.bin set nomod | endif augroup END
を.vimrcに加えると幸せになれるぜ、f*cking my bro.! HAHAHA!!! と書いてある(書いてない)。
*.binのところをcomma-separatedで*.exeだか*.dllと書くとなお幸せ。
これはこれで、そのままでも十分使えるのだけどちょいちょいと手を加えていきます。
vim -bでバイナリエディタ
上のやつそのままだと、.vimrcに加えた拡張子しかバイナリエディタ的に開いてくれない。
まぁ、毎回.binにrenameすればいい、という話ではあるのだけど、vim -bで勝手に切り替わってくれるとなおベターかもしれない。
ということで、&binを&binaryに、BufReadPre以外の*.binを*にすればok。
これでvim -bでファイルを開くとバイナリエディタ的に働きます。
注意点としては普通に開いてから:set binaryなどしないように。最悪ファイルがトびます。
octetを1byteごとに区切る。
xxdの標準だと
echo vim | xxd 0000000: 7669 6d0a vim.
の様に2byteで1octet(?)になっています。
個人的にバイナリエディタといえば1byte 1octet(?)なのでxxdの引数に -g1を追加。
echo vim | xxd -g1 0000000: 76 69 6d 0a vim.
うん。しっくり来る。
functionへの切り分け、カーソル位置の記憶
これはただ単に気になっただけ。
endifの位置とかかなり気持ち悪い。個人的に。
ということで、それぞれ関数に分けます。
augroup Binary autocmd! autocmd BufReadPre *.bin let &binary = 1 autocmd BufReadPost * call BinReadPost() autocmd BufWritePre * call BinWritePre() autocmd BufWritePost * call BinWritePost() function! BinReadPost() if &binary silent %!xxd -g1 set ft=xxd endif endfunction function! BinWritePre() if &binary let s:saved_pos = getpos( '.' ) silent %!xxd -r endif endfunction function! BinWritePost() if &binary silent %!xxd -g1 call setpos( '.', s:saved_pos ) set nomod endif endfunction augroup END
ついでにwrite前後でカーソル位置が移動しないように記憶しておきます。
getpos/setposが無いと%!でカーソル位置が左上に持って行かれます。
これが地味にむかついたので修正
CursorHoldで再フォーマット
実際作業していると削除/挿入、変更などでxxdがread/write時の出力がずれてくることがあります。
欲を言えばリアルタイムに右側のascii出力が変わると便利なのですが、ここはCursorHoldで我慢。
autocmd CursorHold * call BinReHex() function! BinReHex() if &binary let s:saved_pos = getpos( '.' ) let s:modified = &modified silent %!xxd -r silent %!xxd -g1 call setpos( '.', s:saved_pos ) let &modified = s:modified endif endfunction
一旦xxd -rでバイナリに戻して、再びhexに戻しています。
で、今いじりつつ気がついたのですが、xxdって結構ファイル壊しますね...orz
というより、1byte挿入するとその行の一番後ろのoctetが闇に葬り去られる...orz
逆に削除するとフォーマットエラーになるのかその前後、ないしそれ以降が闇に...orz
そりゃスネ夫もorzになりますよ...prz
CursorHoldはやめておいた方がいいかもしれない。
もしくはxxd以外を使うべきかも。
かつてbin2hexとhex2binというソフトを自作したことがあるのですが、今見たら何故かHaskell。
しかも使ってみたらパースエラー...。
Cで書いた記憶があるのだがなぁ...。
そいつを使えば先に挙げたデータが闇に葬られる、ということは無くなりそうなのでそのうちbin2hexとhex2binについてエントリ書くやも。
まぁ、つまりは16進数とバイナリの相互変換できる物があれば、Read/WritePre/Postでちょめちょめするとバイナリエディタになりますよ、ということ。
そういえば.gzとかは標準でvimが展開/再圧縮するようなのでその辺のvimrcを眺めるとまた発見があるかも。
ということで、今回はここまで。
そのうち追記するかもです。