カラースキームを作ってみよう

Vim Advent Calendar 2012 の 131 日目の記事です。

毎日のように Vim を使っているみなさんは、恐らくお気に入りのカラースキームがあったりすると思います。中には一部が気に食わなくて改造してみたり、更にはすでに自作している方もいるかもしれません。
今回は、「カラースキーム作ってみたいけど作り方がよくわからない><」「改造して使ってるけど実はよくわかってないんだよね…」といった方を対象に、カラースキームの作り方について簡単に説明してみようと思います。長くならないように、適時端折っていこうと思います。

始めに

ぶっちゃけてしまうと、最初は既存のカラースキームを改造するところから入るのが楽です。真似して書くとだいたいそれっぽくなるものです。
この記事では 0 から作ることを想定して解説していきますが、チュートリアル的な内容と言うより知識的な解説になっているので、改造だけするにしても参考になるかと思います。

ハイライトグループ

カラースキームを作るというのは、ハイライトグループに対してハイライト(色や書式)を設定していく作業になります。

ハイライトグループは大きく分けて2通りあります。

  • Vim 本体の部品で使うハイライトグループ
    • ステータスラインや行番号、補完のポップアップなど
    • :help highlight-groups
  • 編集領域内で使うハイライトグループ
    • Syntax 機能で使う色、文字列(String)やコメント(Comment)など
    • :help group-name

使われ方が違うだけで、色を設定する上で特別区別する必要はありません。
それぞれで示した :help を見ると、どのようなグループがあるかがわかります。カラースキームを作る際には、ひと通り色を指定するのが理想です(ただし後述のリンクも参照)。指定しなかった場合はデフォルトの色が使用されます。古いカラースキームを使うと補完がキツい紫っぽい色になっているのはあれがデフォルトだからです。

カラースキームファイルを作る

何はともあれ、まずはカラースキームファイルを作りましょう。
その前に、カラースキームの名前を決める必要あります。使える文字などには恐らく特に制限はありませんが、名前がそのままファイル名になります。なので、英数字と -_ 辺りの記号のみで構成しておくのが無難です。また、公開する予定がある場合は既存のカラースキームを検索して被らない名前にしておくと良いでしょう。
決めたら 'runtimepath' 内の colors/{決めた名前}.vim と言うファイルを作成します。例えばカラースキーム名が "thinca" なら、Windows なら ~/vimfiles/colors/thinca.vimLinux 系なら ~/.vim/colors/thinca.vim になります。このファイルにカラースキームの定義を書いていきます。

コンセプトを決める

カラースキームには大きく分けて暗い背景のものと、明るい背景のものがあります。作る際には、どちらのものを作るか決める必要があります。両対応にすることも可能です。
決めたら、以下のテンプレートが使えます。


暗い背景用

let g:colors_name = expand('<sfile>:t:r')
set background=dark
highlight clear

" ... ここに定義を書いていく

明るい背景用

let g:colors_name = expand('<sfile>:t:r')
set background=light
highlight clear

" ... ここに定義を書いていく

両対応

let g:colors_name = expand('<sfile>:t:r')
highlight clear

if &background ==# 'dark'
  " ... ここに暗い背景用の定義を書いていく
else
  " ... ここに明るい背景用の定義を書いていく
endif

g:colors_name には、カラースキームの名前を入れます。こう書いておくと、ファイル名を変えても自動で追従するので便利です。たまに、改造のために既存のカラースキームをコピーして、ファイル名は変えたけどここを変えてないと言うケースを見ます。正しく設定されていないと Vim の動作に支障をきたすことがあるので気を付けましょう。
'background' オプションには "dark" か "light" を設定します。見ての通り、"dark" が暗い背景で、"light" が明るい背景です。
:highlight clear は、定義されている全てのハイライトを消してデフォルトに戻します。この時、'background' の値によってデフォルトが変わるので、先に 'background' を設定しておく必要があります。

補足: syntax reset について

既存のカラースキームを見ると、必ずと言っていいほど highlight clear の下に以下のように書かれています。

if exists("syntax_on")
  syntax reset
endif

今回この記事を書くにあたって調べてみたのですが、この syntax reset で行っている内容は、highlight clear の段階でほぼ行われているようです。少なくとも私には syntax reset が必要な理由が見付けられませんでした。
これが慣習で残っているものなのか、それとも私が何か見落としていて実は普通に必要なものなのかはちょっとわかりません。もし必要な理由をご存知の方がいたら教えていただけると助かります。
気になる人は、syntax reset も書いておくとよいです。既存のカラースキームではほぼ書かれているので、実害はないはずです。

ハイライトの設定方法

いよいよハイライトを設定します。:highlight コマンドを使って以下のようにします。

" highlight {group-name} {key}={arg} ...
highlight Comment ctermfg=Cyan guifg=#80a0ff

この例では Comment グループの文字色を設定しています。ctermfg は CUI 版の Vim で使われる文字色、guifg は GUI 版の Vim で使われる文字色を指します。
このように、CUI 版と GUI 版の設定は別々に行います。CUI 版は特に対応が面倒なので、必要なければ GUI 版のみに対応したカラースキームを作っても大丈夫です。幸い、CSApprox など、GUI 版のカラースキームを CUI 版に変換するようなものもあるので、複雑なものでなければこのようなものを使うのも手です。
実際には、この highlight コマンドを設定したいグループの数だけ列挙することになります。もちろん Vim script なので、必要であれば if や :execute でより複雑な定義もやろうと思えば可能です。


以下では、どのような設定ができるのかをもう少し詳しく見ていきます。
:highlight では文字の属性や、前景色(文字色)、背景色が設定できます。
文字の属性を指定することで、太字にしたり、斜体にしたり、下線を引いたりできます。CUI 版では、端末によって制限がある場合が多いです。

" 指定できるパラメータは :help attr-list を参照
highlight Comment cterm=italic gui=italic

前景色、背景色は、CUI 版では色名か色番号、GUI 版では色名か #RRGGBB 形式で指定できます。
色名については、:help cterm-colors や :help gui-colors などを参照してください。環境依存ですが、:help win32-colors や :help rgb.txt なども使えます。

" 例なので混ぜて使っているが、指定する形式は統一した方が良い
highlight ErrorMsg cterm=bold ctermfg=231 ctermbg=Red gui=bold guifg=#ffffff guibg=Red

特に端末で 256 色のものを作ろうと思ったら名前での指定はできないので色番号の指定が必須になります。かなり大変なので、先ほど紹介したツールなどで GUI 版から変換するのがおすすめです。
また、見ての通り、属性や色を複数同時に指定できます。指定しなかったものについては変化しません。なので、1つのハイライトグループの定義を分けて書くことも可能です。

ハイライトのリンクについて

:help group-name で見られる構文グループの一覧ですが、説明を読むと、リンクされている、などと書かれています。
ハイライトにはリンク機能があり、特定のハイライトグループが別のハイライトグループと同じになるように設定することができます。
例えば、Constant については help に以下のように書かれています。

        *Constant       o 定数
         String         o 文字列定数: "これは文字列です"
         Character      o 文字定数: 'c', '\n'
         Number         o 数値定数: 234, 0xff
         Boolean        o ブール値の定数: TRUE, false
         Float          o 不動小数点数の定数: 2.3e10

これは、ここに書かれている Constant 以下のハイライトはデフォルトで Constant にリンクしている、つまり特に設定していない場合は Constant と同じようにハイライトされることを示しています。
具体的には Vim script で以下のように定義されています。

highlight default link String    Constant
highlight default link Character Constant
highlight default link Number    Constant
highlight default link Boolean   Constant
highlight default link Float     Number

これはつまり、Constant などの help で * が付いているものだけを最低限定義しておけばとりあえず一通りハイライトされることを意味しています。もちろん、全てに対してハイライトを細かく設定することも可能です。
ちなみに、画面内のどの要素が Constant でどの要素が String なのか、などは Syntax の定義によります。

おまけ: カラースキームと Syntax

色を付ける対象であるハイライトグループの一覧は :help highlight-groups と :help group-name で確認できることはすでに説明しました。しかし実際には、このリストのものに限らず任意の名前のグループに対してハイライトを設定できます。これを利用して、一歩進んだカラースキームも作れます。
Vim では Syntax 機能を使って、編集中のテキストの各箇所に構文グループを割り当てることができます。例えば、テキストのここからここまでは Function、この単語は Statement、と言った具合です。ここで割り当てた構文グループの名前は、先ほど説明したハイライトグループと同じものになります。つまり、構文グループ名に対して直接色を設定できます。
この構文グループ名は、通常はファイルタイプを接頭子にした名前が使われます。例えば vim なら、vimString vimComment と言った感じです。なので実際には、先ほど説明したハイライトのリンク機能を使ってリンクの設定をしています。

" vimString は String グループで、vimComment は Comment グループでハイライト
highlight link vimString String
highlight link vimComment Comment

これはつまり、特定の言語に対して細かく色を変えることも可能だということです。例えば Ruby では、文字列が rubyString、正規表現が rubyRegexp になっています。これらに直接ハイライトを設定することで、別々にハイライトすることも可能です。

※わかりやすくするためにあえて全然違う色にしてます

最後に

最初にも書きましたが、既存のカラースキームを見るとどんな感じか雰囲気が掴めると思います。
最後に便利サイトを紹介します。Vim の画面から直接色をいじってカラースキームが生成できます。
http://bytefluent.com/vivify/
いじれない部品もあったりして網羅的ではないのですが、各部位がなんという名前のハイライトグループか、などが触っててわかるのが良いです。簡単なカラースキームならこれでも作れそうです。


さて、いかがでしたか。皆さんもぜひ、自分用のこだわりカラースキームを作ってみてください!
ちなみに私自身は配色センスが皆無なため自作はおろか改造もしてません。残念ですね。