🙏

iceberg.vimを壊してしまった話

2022/12/07に公開

はじめに

こんにちは、あろーです。

半年前くらいに VSCode から Vim へ移行したばかりの初心者です。
現在は Neovim をメインに使っています。

本来は Vim に入門した話を書こうと思っていたのですが、自戒の念を込めてこの記事を書いています…。

iceberg.vim って?

iceberg.vim はcocoponさんが開発されている、Vim・Neovim 対応のカラースキームです。
ダークブルーを基調としていて視認性がよく、かっこよくてかわいいので愛用しています。

iceberg

https://cocopon.github.io/iceberg.vim/

何をしたのか

シンタックスハイライトにnvim-treesitterを使用している環境で、正しく色がつかなくなっていた問題を修正する PR を出しました。

修正前
色がつかなくなっている様子

修正後
本来はこうなっているべき

https://github.com/cocopon/iceberg.vim/pull/107

原因

原因はシンプルで、最近取り込まれた nvim-treesitter のハイライトグループ名の変更に iceberg.vim が対応できていなかったからでした。

具体的には、TS から始まっていた名前が @ から始まる名前に変更されています。

詳しい変更内容については以下のリンクをご参照ください。

https://github.com/nvim-treesitter/nvim-treesitter/pull/3656
https://github.com/nvim-treesitter/nvim-treesitter/issues/2293#issuecomment-1279974776

経緯

「置き換わっただけなら、カラースキームの方でも置き換えればいけそう!」
と思ったので、愚直に置き換えました。

変更箇所

その後、ちょっと調整したりして…

追加箇所
既存のTS*のハイライトグループを消すと後方互換性が壊れるので戻した

無事にマージしていただけました ✌️

コメント

壊れた

と喜んでいたのも束の間、以下のような Issue が立ちました。

https://github.com/cocopon/iceberg.vim/issues/108

「Vim で読み込んだ際に警告 W18: Invalid character in group name happens が出まくる」という内容です。

どう考えても私の行った変更が原因なので、急いで調査に取り掛かりました…。

なぜ壊れたのか

結論から言うと、原因はVim と Neovim とでハイライトグループ名に使える文字が異なることでした。

Vim で使用できる文字は [a-zA-Z0-9_] ですが、Neovim v0.8 から .@ を足した [a-zA-Z0-9_.@] が使用できるようになっています。

後にコメントで教えていただいたのですが、リリースノートの Breaking changes にしっかりと記載されていました。

https://github.com/neovim/neovim/releases/tag/v0.8.0

Vim(もしくは Neovim v0.7 以前)では @ が使用できないため Invalid character in group name という警告が出ていた、という訳です。

修正する

上記の理由から、@* のハイライトグループを Neovim v0.8 以降の場合にのみ定義するよう修正すれば良さそうです。

iceberg.vim はpgmnt.vimというテンプレートエンジンで生成する形を取っているので、そちらのコードを触る必要があります。

src/iceberg.vim

「今後、Treesitter 以外にも Neovim に依存したハイライトグループ名を使うプラグインがあるかも」と思ったので、追加しやすいよう該当する部分を関数にまとめました。

はじめに出した PR とは異なり、元々定義されていた TS* のハイライトグループにリンクさせる形を取っています。

iceberg.vim
function! s:create_neovim_08_links() abort
  let links = []

  call add(links, pgmnt#hi#link('@attribute', 'TSAttribute'))
  call add(links, pgmnt#hi#link('@boolean', 'TSBoolean'))
  call add(links, pgmnt#hi#link('@character', 'TSCharacter'))
  call add(links, pgmnt#hi#link('@comment', 'TSComment'))
  call add(links, pgmnt#hi#link('@constructor', 'TSConstructor'))
  call add(links, pgmnt#hi#link('@conditional', 'TSConditional'))
  call add(links, pgmnt#hi#link('@constant', 'TSConstant'))
  call add(links, pgmnt#hi#link('@constant.builtin', 'TSConstBuiltin'))
  call add(links, pgmnt#hi#link('@constant.macro', 'TSConstMacro'))

  " 省略...

  return links
endfunction

create_context() の戻り値がテンプレートに埋め込まれるので、ここで先ほど作った関数を呼び、戻り値に追加します。

iceberg.vim
 function! s:create_context() abort
   " 省略...
   let neovim_08_links = s:create_neovim_08_links()

   return {
         \   'modified': strftime('%Y-%m-%d %H:%M%z'),
         \   'dark_rules': d.rules,
         \   'dark_neovim_term_defs': d.neovim_term_defs,
         \   'dark_vim_term_defs': d.vim_term_defs,
         \   'light_rules': l.rules,
         \   'light_neovim_term_defs': l.neovim_term_defs,
         \   'light_vim_term_defs': l.vim_term_defs,
         \   'links': links,
+        \   'neovim_08_links': neovim_08_links,
         \ }
 endfunction

src/template.vim

テンプレートへ create_context() に新しく追加した戻り値の名前を埋め込みます。

has('nvim-0.8') で Neovim v0.8 以上なのかを取得できる[1]ので、それを使って分岐させています。

template.vim
 " 省略...
 {{ links }}

+ if has('nvim-0.8')
+   {{ neovim_08_links }}
+ endif

 if !has('nvim')
   hi! link SpecialKey Whitespace
 endif

これで、今度こそ完了です!

https://github.com/cocopon/iceberg.vim/pull/110

最後に

Neovim について「なんか Vim を強くしたやつ」くらいの認識でいたので、改めて両者の違いを調べる良いきっかけになったなと思います。

また、vim-jpの Slack[2]でも今回のハイライト周りの件が話題にあがっており、Neovim 本体の Issue・PR を読みつつお話されていて、とても勉強になりました。

最後になりますが、今回 PR の対応をしてくださった cocopon さんをはじめ、コメントにてフォローしてくださった方々には頭が上がりません。ありがとうございました…!

脚注
  1. こちらのコメントで教えていただきました 🙏
    https://github.com/cocopon/iceberg.vim/pull/110#issuecomment-1316889285 ↩︎

  2. 参加はこちらから…!
    https://vim-jp.org/docs/chat.html ↩︎

Discussion