Vim/Neovimでハイライトグループ設定をマージするコマンドを作った
経緯
Vimでハイライトグループを設定するときに、重複する部分を既存のものから流用できないかと考えていました。
例えば、文字を赤くするRed
というグループと、文字を太くするBold
というグループがあるとします。
太い赤文字を表すRedBold
というグループを作りたいと思ったら、通常は以下のようにhighlight
コマンドを使って明示的に設定する必要があります。
highlight Red guifg=#ff0000
highlight Bold gui=bold
highlight RedBold guifg=#ff0000 gui=bold
これだと明らかに記述が重複しているので、次のように書きたいところです。
highlight Red guifg=#ff0000
highlight Bold gui=bold
highlight link RedBold Red Bold " cause error!
しかし、highlight link
コマンドはエイリアス的な使い方が想定されているもので、from-group
とto-group
の2つの引数しか取ることができません。
vim-jpで質問してみたところ、このようなマージ機能は用意されていないとのこと。
そこで、処理を自作できないか検討しました。
MergeHighlight
ということで作ってみました。
以下をお手持ちの設定ファイル(.vimrc
とかinit.vim
とか)に定義してください。
MergeHighlight
コマンドと、それが呼ぶs:MergeHighlight()
関数を定義します。
最初はHighlightMerge
にしていたのですが、組み込みのhighlight
と補完が被ってしまうため、MergeHighlight
という名前にしました。
つかいかた
第一引数に新しく定義するハイライトグループの名前、第二以降の引数にマージ元のハイライトグループの名前を取ります。
MergeHighlight {new-highlight-name} {source-highlight-names}
{source-highlight-names}
の設定を統合したハイライトグループを新しく定義します。
関数内では引数の確認やフィルター処理も行っていますが、本質的にはexecute('highlight ' . val)
で取得した設定文字列を連結しているだけです。
設定対象(ctermfg
とかguifg
とか)が重複した場合は、最後のものが有効(これはhighlight
コマンドの仕様)です。
具体的な使い方は以下のとおりです。最初に示したイメージと同じです。
highlight Red guifg=#ff0000
highlight Bold gui=bold
MergeHighlight RedBold Red Bold
" same as ↓
" highlight RedBold guifg=#ff0000 gui=bold
注意点
上記のコード中にコメントしていますが、link
かcleared
になっている色設定は読み飛ばします。
cleared
はともかくlink
の方はリンク先を参照することもできそうなのですが、リンクが連鎖している可能性があるため再帰が必要になりますし、辿っていった先が存在しないときのエラー処理なども考えると、結構複雑な実装になりそうと感じたためです。
自分で使うぶんには読み飛ばしても問題ないかな、と思っています。
おわりに
Vimの色設定をマージするコマンドを作ることができました。
「Red
とBlue
とYellow
とGreen
のそれぞれにBold
とItalic
を組み合わせて、さらにLightBackground
とDarkBackground
を反映させたグループを作りたい…!」みたいなことがやりやすくなると思います。
なお、紹介したs:MergeHighlight()
関数はVim scriptを使って書いていますが、Neovimであればluaでも書けると思います。
よりスマートな解決法があればコメントいただけると幸いです。
Discussion