初めに
前回バッファー内容を実行して動きを理解したらVimスクリプトが書きたくなるという記事でした。
今回は実際にやってみよう!ということで
最初は小さな不満を小さく解決していくのが良い経験になると思います
折り畳み
具体的なVimスクリプトのさわりとして、折り畳み(fold)をさわってみたいと思います。
python風のインデントはデフォルトでは折り畳みをしてくれないと思います。
まずは単純な方法で実装する方法を試してみましょう。
既存の機能を試してみる
まず普通にもともとの機能で充足しないかvimのマニュアルを見ます
難しい様であればネットや昨今であればAIに聞いてみるのがよいと思います
AIにざっと聞くといくつか候補が上がると思うのでそれを検証していこうと思います。
- foldmethod=indent が適している一般的らしい
- foldexprを使用して独自関数で折り畳みする
前回と同様に奇麗なvimの立ち上げは以下です。
TABキーを押すとカレント行の記載がvimコマンドとして実行されます
vim -u NONE -s <(echo -e ':set cpo-=<\n:nnoremap <TAB> :execute getline(".")<CR>') foobar.txt
以下をvim上に貼り付けて:set number+
の行から[TAB]
キーを押して実行してださい
※ 都合上「必要リスト」の行を1行目となるようにしてください
必要リスト{{{
カレー{{{
カレールウ
豚こま切れ肉 xxグラム
にんじん x本
玉ねぎ x個
じゃがいも x個}}}
ハンバーグ{{{
挽き肉 xxグラム
パン粉 xxグラム
牛乳 xxcc
ナツメグ 少々}}}
}}}
" 「必要リスト」が1行目になるようにしてください
" ここの下の行から1行づつ<TAB>を押して実行していきます。
:set number! " 行番号表示(トグルします)
:set foldcolumn=5 " 折り畳み表示カラム桁数
:set foldenable! " 折り畳み
:set shiftwidth=4 " インデント桁数
:set foldmethod=indent " 折り畳み方法
" zc、zo、zC、zOなどでカーソル行の折り畳みを閉じたり開いたり
" できるので試してみてください
:execute "normal zR"| " 全行折り畳みを開く
:execute "2normal zc"| " カレー行で1段クローズ
:execute "normal zR"| " 全行折り畳みを開く
" ちょっとイメージとずれてますね
" マーカー{{{ }}}で折り畳みを指定してますのでその方式にしてみましょう
:set foldmethod=marker " 折り畳み方法
:execute "normal zR"| " 全行折り畳みを開く
:execute "8normal zc"| " ハンバーグ行で1段クローズ
:execute "2normal zc"| " カレー行で1段クローズ
:execute "normal zR"| " 全行折り畳みを開く
" イメージどおりですが、毎回{{{ }}}を置くのは見栄えが悪いし
" なにを取捨選択するのかこのタイミングが一番楽しい時間でもあります、、、
:折り畳みのヘルプはこちら
:help fold.txt
indexは惜しいけど違う。
インデントが深くなった1行目に集約するようになる様です。ひとつ上で集約出きるといい感じになるのでは無いかと。
次行のインデントが深くなって入れば、深くなっているものを設定すれば良いでしょうか。
自作の折り畳み関数で制御してみます。先ほどの下に以下を貼り付けてください。
:" 上から戻ってきて折り畳みを開きます
:execute "normal zR"| " 全行折り畳みを開く
:" 複数行の実行マクロ
:vnoremap <TAB> y<Bar>:@0<CR>
:" 折り畳みの自作関数、SHIFT-v でendfunction まで選択して[TAB]キーを押してください
:function! Exprfunc(lnum) abort
:let i=indent(a:lnum )/getbufvar("","&shiftwidth")
:let j=indent(a:lnum + 1)/getbufvar("","&shiftwidth")
:if j > i
:return '>' . j
:else
:return i
:endif
:return 0
:endfunction
:set foldexpr=Exprfunc(v:lnum) " 折り畳み関数の定義
:set foldmethod=expr " メソッドとして関数の使用を設定
:execute "8normal zc"| " ハンバーグ行で1段クローズ
いい感じです。空行があると壊れてしまうのですがそこは宿題ということで
では
おまけ
個人的にお気に入りの表示を変える方法はしたです
:" 個人的な趣味で表示内容を変更します
:" ...として折り畳みを表します
:set foldtext=getline(v:foldstart).'\ ...'
:" ...以降の文字。行末に空白があります
:set fillchars=fold:\
:" 色の変更
:highlight Folded ctermfg=LightGreen ctermbg=NONE
また今回下のような感じで各動作を確認しました。ご参考に
:" 折り畳みの作成系
:" foldenable " 折り畳み状態のオンオフを制御
:set foldenable? " 現在値の表示
:set foldenable& " デフォルト値を設定
:set foldenable " 折り畳みを有効化する
:set nofoldenable " 折り畳みを無効化する。すべての折りたたみは開かれ一時的に折り畳みの情報は消えるがクリアされない
:set foldenable! " 折り畳み有効無効を反転する
:" ノーマルコマンド|を入れないと空白によりカーソル移動してしまう、
:execute "normal zN"| " 有効化
:execute "normal zn"| " 無効化
:execute "normal zi"| " 反転
:" foldmethod " 折り畳み方法を指定
:set foldmethod? " 現在値の表示
:set foldmethod& " デフォルト値を設定(折り畳みの情報はクリアされない)
:set foldmethod=manual " 手動zfなどで指定
:set foldmethod=indent " インデント表記に基づいて折り畳みされる
:set foldmethod=marker " {{{/}}}で指定する
:set foldmethod=expr " 自作関数で指定する
:set foldmethod=syntax " 構文強調により折り畳みを定義する
:" よく使うノーマルコマンド
:execute "normal zc"| " 1段閉じ
:execute "normal zC"| " 階層閉じ
:execute "normal zo"| " 1段開き
:execute "normal zO"| " 階層開き
:execute "normal zM"| " 全閉じ
:execute "normal zR"| " 全開き