🎨

Vim/Neovimでハイライトグループ設定をマージするコマンドを作った

2021/12/02に公開

経緯

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-groupto-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

注意点

上記のコード中にコメントしていますが、linkclearedになっている色設定は読み飛ばします。
clearedはともかくlinkの方はリンク先を参照することもできそうなのですが、リンクが連鎖している可能性があるため再帰が必要になりますし、辿っていった先が存在しないときのエラー処理なども考えると、結構複雑な実装になりそうと感じたためです。
自分で使うぶんには読み飛ばしても問題ないかな、と思っています。

おわりに

Vimの色設定をマージするコマンドを作ることができました。
RedBlueYellowGreenのそれぞれにBoldItalicを組み合わせて、さらにLightBackgroundDarkBackgroundを反映させたグループを作りたい…!」みたいなことがやりやすくなると思います。

なお、紹介したs:MergeHighlight()関数はVim scriptを使って書いていますが、Neovimであればluaでも書けると思います。
よりスマートな解決法があればコメントいただけると幸いです。

Discussion