折り畳み嫌いの男が一夜でFolding freakにまでなった話

続編→折り畳み嫌いの男が一夜でFolding freakにまでなった話2


Vim Advent Calendar 2011 23日目天皇誕生日担当は私@LeafCageです。


みなさん折り畳み(Fording)は使ってるでしょうか?
私は折り畳みが嫌いでした。

折り畳みがダメな理由は大きく2つあります。

  • 見た目が悪い
  • 操作性が悪い

この2つをカイゼンして快適な折り畳み環境を構築することにします。

見た目のカイゼン

まず、見た目についてです。
Vim標準の折り畳み表示はインデントが崩れる、最初の行の内容が分かりにくいということで直感的ではありません。
そこで折り畳みテキストを生成する関数を差し替えて、より自分に望ましいように表示を変えてしまいましょう。
標準ではset foldtext=foldtext()になっていますが、これを自分で用意した関数に差し替えます。
適用例は以下の感じです。

Before

After


Before

After

全て展開した図(Afterだと折り畳んでいる状態でもインデントが分かる)


折り畳んでいてもインデントが識別でき、必要な情報も分かりやすく表示されるようになりました。(後ろに[行数 折り畳みレベル]が表示されるようになっています)
私が使った関数は以下にあります(こちらのものを参考にさせて頂きました)。
LeafCage/foldCC.vim · GitHub

set foldtext=FoldCCtext()でこの関数を使うようになります*1。他にset foldcolumnでウィンドウ左端にフォールディングのガイドを出現させ、set fillcharsのFoldのfill文字を削除しておくといいでしょう。

set foldtext=FoldCCtext()
set foldcolumn=5
set fillchars=vert:\|

折り畳みテキストの作り方については:h fold-foldtextを見るといいでしょう。
かなりわかりやすく書かれています。

折り畳みの色はhighlight Foldedで、左端のフォールディングのガイドはhighlight FoldColumnで設定できます。
見やすく、かつ一目で折り畳みとわかる色を設定しておくといいでしょう。

hi Folded gui=bold term=standout ctermbg=LightGrey ctermfg=DarkBlue guibg=Grey30 guifg=Grey80
hi FoldColumn gui=bold term=standout ctermbg=LightGrey ctermfg=DarkBlue guibg=Grey guifg=DarkBlue

操作性のカイゼン

次に操作性についてです。
標準ではFolding関係にはzで始まるコマンドが用意されていますが、明らかに押しづらいし無理に使うと小指を破損するのでよく使うコマンドは別のキーにマップしましょう。

  noremap [space] <nop>
  nmap <Space> [space]

  noremap [space]j zj
  noremap [space]k zk
  noremap [space]n ]z
  noremap [space]p [z
  noremap [space]h zc
  noremap [space]l zo
  noremap [space]a za
  noremap [space]m zM
  noremap [space]i zMzv
  noremap [space]r zR
  noremap [space]f zf

]z[zは折り畳みを閉じずに折り畳みから抜けたいときに便利です。やたら巨大な折り畳みの末尾や先頭を確認したいときに使っています。
折り畳みのブラウジングにはzjzkを使います。
zMzvは便利です。今現在カーソルがあるところ以外の折り畳みを閉じてくれます。
Folding freakになってくると自分が編集しているところ以外のフォールディングが開いているのが許せなくなってきます。また、単に現在地の折り畳みを展開するのにも使えます。
何かを参照しながら編集するときはウィンドウ分割も併用するといいでしょう。
一方のウィンドウでは折り畳み、他方のウィンドウで同じバッファの折り畳み箇所を開いた状態にするということが可能です。
zf(折り畳みを作成)とzd(折り畳みを削除)はFolding freakにとって必須コマンドです。私はzfをほとんどビジュアル選択で作っていますが、'kana/vim-textobj-indent'*2を使うとzfiiで同一インデントの固まりを一気にfoldすることができます。

foldmethod

折り畳みの話をするときにこれをまず初めに言うべきでしたが、私はfoldmethodはmarkerにしています。こうしておくと'{{{'のある行でフォールディング開始、'}}}'のある行でフォールディング終了します。

foldmethodについて
manual	    折り畳みは手動で設定する。(.viminfoファイルに情報が記録される?)
indent	    等しいインデントの行で折り畳みを作る。
expr	    オプション 'foldexpr' で深さを設定する。 
marker	    マーカーで折り畳みを指定する。
syntax	    構文強調表示のキーワードを使って指定する。
diff	    変更されていないテキストを折り畳む。

フォールディングの開始と終了位置を他の環境で開いたときも変わらずに開くことができる、自分の望む位置に折り畳みを作ることができるということで私はmarkerをデフォルトにしています。

set foldmethod=marker

秘密兵器

折り畳みが複数ある巨大なファイルでしばしば起きることといえば、自分が今どこにいるのか分からなくなる、いわゆる迷子です。
そこで迷子を解消するための秘密兵器を用意しました。
今自分がいる折り畳みとその親を教えてくれる関数、FoldCCnavi()です。
これは先ほどのファイルに含まれています。

  noremap [space]g :echo FoldCCnavi()<CR>


このように、自分が今どの階層にいるのかをコマンドラインで教えてくれます。
(この例だと、「キーマップ」という折り畳みの中の、「設定・fixに近い」という折り畳みの中の「*で次の単語に移動させない」という折り畳みにいることが分かります)

自分がどの折り畳みの中にいるのか分かれば自分の位置についておおよその見当がつけられます。いつでも自分の位置を確認できるので、巨大なファイルを編集・閲覧しているときも妙な安心感があります。

zfで挿入される折り畳みが/* */のコメントで囲まれてるのが気にくわない場合

'commentstring'を設定しましょう。
何も設定していないファイルだとzfで/*{{{*/ /*}}}*/が挿入されます。
これは標準でset commentstring=/*%s*/になっているからです。(これは対象文字列%sを/*と*/で挟んだらコメントであるということを示しています)
ファイルタイプ定義ファイル(.vim/ftdetect/の中にあるファイル)やautocmdで特定のファイルのcommentstringを設定しましょう。
例えば、.vimperatorファイルではvimと同じコメント形式を使いたいので、

autocmd BufRead,BufNewFile .vimperatorrc  setfiletype Vimperator|setlocal commentstring=\ \"%s

とします。
また、何も設定していないファイルを開いたときの標準コメントアウト形式が/* */であることは滅多にないので、.vimrcに以下のように書いておきます。

set commentstring=%s

これで、何も設定していないファイルにはzfで純粋なfoldmarkerのみが挿入されるようになりました。



私は、つい最近Foldingについて設定を整えましたが、それまでとファイル操作の環境が大きく変わりました。
Foldingを活用すると1つのファイルで階層的なテキストが書けて管理が楽になります。

おまけ

unite-outlineに折り畳みを表示する機能があるそうです。
:Unite outline:foldingsで折り畳み一覧を表示できるそうですが、作者様によると出来が良ろしくないので非推奨の機能らしいです。


24日目、イヴの担当は@hinagishiさんです。
それでは良いクリスマスイヴを。

*1:この関数はあまりに幅が狭いウィンドウで使うと表示がおかしくなります。

*2:'kana/vim-textobj-user'(https://github.com/kana/vim-textobj-user)が必要です