Neovim の折りたたみを使いやすくカスタマイズする
Vim に標準で備えられている折りたたみ機能について、ちょくちょく使ってはいたものの雑な設定しかしていない状態でした。 今回ユーザマニュアルを読みつつ設定を見直し、ある程度使いやすいと感じる状態になったのでその記録を残します。
そもそもどういう用途で折りたたみを使うか
まず、どういう用途で折りたたみを使うかを改めて言語化してみました。
ここは人によって様々かと思いますが、自分の場合は以下のような用途だと思われました。
- 大きなコードの全体像をざっくり把握する
- 自分が修正しようとしている箇所と関係ないところを隠す
こういった用途で使いやすいようにカスタマイズしていきます。
インデント基準で折りたためるようにする
ユーザマニュアル を読むと折りたたみ方法としていくつかの選択肢がありますが、全体像の把握や不要な詳細を閉じるという用途においては "indent"
が最も適していると思います。
-- init.lua
vim.opt.foldmethod = "indent"
ただ、このままだと Vim でファイルを開いたときにすでに折りたたまれている状態となってしまい、それは望むところではありません。
これは、折りたたみの深さを設定する foldlevel
という値がデフォルトで 0 となっていることが原因ですので、以下のように大きな値を設定しておきます。
-- init.lua
vim.opt.foldmethod = "indent"
vim.opt.foldlevel = 99 -- 追加
やや無理矢理感はありますが、致し方なさそうです。
S-Tab
で閉じ、Tab
で開くキーマッピング
さてここまでの設定で事前準備ができました。
次は折りたたんだり開いたり、というところをサクサクとできるようにしていきます。
ここのキーマップは少々悩みましたが、自分は S-Tab(Shift + Tab)
でカーソル位置を基準に折りたたむようにし、Tab
で開くようにしました。
-- init.lua
vim.keymap.set("n", "<Tab>", "zo")
vim.keymap.set("n", "<S-Tab>", "zc")
vim.keymap.set("n", "<Leader><Tab>", "zR")
vim.keymap.set("n", "<Leader><S-Tab>", "zM")
応用として、<Leader>S-Tab
ですべて折りたたみ、<Leader>Tab
ですべて開くようにしました。これは全体像を把握するという目的に対してマッチしていて、<Leader>S-Tab
ですべて閉じた後に Tab
で徐々に開いて眺めていく、ということができます。
foldtext
で折りたたんだ際の表示を読みやすくする
最後に、折りたたまれた箇所の表示を少し変更します。
変更するには、foldtext という設定値に自作の関数を渡してあげます。次のようにしてみます。
-- init.lua
function Foldtext()
local line = vim.fn.getline(vim.v.foldstart)
local count = vim.v.foldend - vim.v.foldstart + 1
return string.format("%s (%d lines folded)", line, count)
end
vim.opt.foldtext = "v:lua.Foldtext()"
vim.opt.fillchars = { fold = " " } -- 折りたたんだ際のあまりの部分をスペースにする
fillchars という設定値も変更して折りたたんだ際の余白の表示文字を変更しています。これで、折りたたんだ際に以下のような表示になります。
情報量としてはあまり変わっていませんが、行頭の位置が折りたたむ前と後でずれなくなったのでより見やすくなった気がします。ここはもう少し改良の余地はあるかもしれません。
まとめ
Neovim の折りたたみ設定を改善した話でした。
折りたたみ機能自体あまり使っている人は多くない印象ですが、用途がマッチした人の参考になれば幸いです。
最終的な init.lua の状態を載せて終わります。
-- init.lua
function Foldtext()
local line = vim.fn.getline(vim.v.foldstart)
local count = vim.v.foldend - vim.v.foldstart + 1
return string.format("%s (%d lines folded)", line, count)
end
vim.opt.foldmethod = "indent"
vim.opt.foldlevel = 99
vim.opt.foldtext = "v:lua.Foldtext()"
vim.opt.fillchars = { fold = " " }
vim.keymap.set("n", "<Tab>", "zo")
vim.keymap.set("n", "<S-Tab>", "zc")
vim.keymap.set("n", "<Leader><Tab>", "zR")
vim.keymap.set("n", "<Leader><S-Tab>", "zM")