usr_44.txt For Vim バージョン 9.1. Last change: 2017 May 06
VIM USER MANUAL - by Bram Moolenaar
構文ファイルを作成する
Vim は 200 種類以上ものファイルを強調表示できます。強調表示されないファイルを
見つけた場合は、本章を読んで、ファイルを強調表示する方法を調べてください。リ
ファレンスマニュアルの :syn-define も参照してください。
44.1 基本的な syntax コマンド
44.2 キーワード
44.3 マッチ
44.4 リージョン
44.5 構文アイテムを入れ子にする
44.6 グループの並び
44.7 その他の引数
44.8 クラスタ
44.9 他の構文ファイルをインクルードする
44.10 シンクロナイズ
44.11 構文ファイルをインストールする
44.12 ポータブルな文法定義ファイル
次章: usr_45.txt 言語を選択する
前章: usr_43.txt ファイルタイプを使う
目次: usr_toc.txt
==============================================================================
44.1 基本的な syntax コマンド
既存の構文ファイルを土台にすることで多くの時間を節約できます。望みのものに近い
言語の構文ファイルを $VIMRUNTIME/syntax から探してください。それらのファイルを
見れば、構文ファイルの基本的な構造がわかると思います。内容を理解するには本章を
読んでください。
基本的なことから説明します。構文定義を開始する前に、古い定義をクリアする必要が
あります:
最終的な構文ファイルではこのコマンドは必要ありませんが、いろいろと試したいとき
には便利です。
本章の説明はかなり簡略化されています。構文ファイルを書いて、それを他人に使って
もらう場合は、本章を最後まで読んで詳細を理解してください。
定義された構文アイテムを一覧表示する
現在定義されている構文アイテムを表示するには、次のコマンドを使います:
実際に定義されている構文アイテムを確認することができます。新しい構文ファイルを
作っていて、いろいろと試しているときに便利です。また、それぞれの構文アイテム
は、実際の表示と同じ色で表示されるので、何がどうなっているかも確認できます。
特定の構文グループのアイテムを一覧表示するには次のようにします:
これはクラスタ (44.8参照) を一覧表示することもできます。その場合は名前に @
を付けてください。
大文字と小文字の区別
Pascal などの言語は大文字と小文字を区別しません。C などの言語は大文字と小文字
を区別します。次のコマンドで区別するかしないかを指定できます:
"match" を指定すると大文字と小文字は区別されます。その場合、"int" と "Int" と
"INT" はそれぞれ違うものになります。"ignore" を指定した場合は、"Procedure" と
"PROCEDURE" と "procedure" は同じ扱いになります。
":syntax case" コマンドは構文ファイルのどこにでも書くことができ、それ以降の構
文定義に作用します。ほとんどの場合、":syntax case" コマンドは構文ファイルに一
つだけ書きますが、大文字と小文字を区別する要素と区別しない要素を両方もつような
特殊な言語の場合には、ファイルのいたるところで ":syntax case" コマンドを書くこ
ともできます。
==============================================================================
44.2 キーワード
最も基本的な構文要素はキーワードです。次のように定義します:
{group} は構文グループの名前です。":highlight" コマンドを使うことで {group} に
色を割り当てることができます。{keyword} は実際のキーワードです。いくつか例を示
します:
"xType" と "xStatement" がグループ名です。習慣的に、グループ名の先頭にはファイ
ルタイプ名が付けられます。この例では x 言語 (そういう言語があるのではなく単に
eXample の x) の構文を定義しています。例えば "csh" スクリプト用の構文ファイル
なら "cshType" という名前になります。つまり、'filetype' の値と同じものを先頭に
付けます。
この例では "int" と "long" と "char" が同じ方法で強調表示され、"if" と "then"
と "else" と "endif" が別の同じ方法で強調表示されます。次に、x グループ名と
Vim の標準名を関連付ける必要があります。次のようにします:
"xType" を "Type" で強調表示し、"xStatement" を "Statement" で強調表示します。
標準名については group-name を参照してください。
特殊なキーワード
キーワードとして使われる文字は 'iskeyword' オプションに指定されていなければな
りません。それ以外の文字を使った場合、その単語は決してマッチしません。Vim はそ
のことについて警告メッセージを出しません。
例題の x 言語は '-' 文字をキーワードとして使えます。それは次のように設定しま
す:
":setlocal" コマンドを使って、カレントバッファだけ 'iskeyword' を変更していま
す。この設定によって "w" や "*" などのコマンドの動作も変更されます。動作を変更
したくない場合は、キーワードではなくマッチを使ってください(次節で説明します)。
x 言語では短縮形も使えます。例えば、"next" は "n"、"ne"、"nex" に短縮できま
す。次のコマンドでそれを定義できます:
これは "nextone" にはマッチしません。キーワードは常に単語全体にのみマッチしま
す。
==============================================================================
44.3 マッチ
もう少し複雑なものを定義してみましょう。普通の識別子にマッチさせるため、マッチ
構文アイテムを定義します。次の例は、すべての文字が小文字の単語にマッチします:
Note:
キーワードは他の構文アイテムより優先されます。"if" や "then" などの
キーワード (上述の ":syntax keyword" コマンドで定義したもの) は、
xIdentifier にもマッチしますが、キーワードとして扱われます。
最後の部分はパターンです。これは検索で使用するものと同じです。// を使ってパ
ターンを囲みます (":substitute" コマンドと同じ)。+ や " など、他の文字を使うこ
ともできます。
次はコメント用のマッチを定義してみます。x 言語では "#" から行末までがコメント
になります:
すべての検索パターンが使えるので、マッチを使うことで非常に複雑なものを強調表示
できます。検索パターンについては pattern を参照してください。
==============================================================================
44.4 リージョン
例題の x 言語では、文字列をダブルクォートで囲みます。文字列を強調表示するため
にリージョン (領域) を定義します。それにはリージョンの開始 (ダブルクォート) と
リージョンの終了 (ダブルクォート) が必要です。定義は次のようになります:
"start" と "end" に指定したパターンは、リージョンの開始と終了を探すために使用
されます。しかし次のような文字列があったらどうなるでしょうか?
"A string with a double quote (\") in it"
これはうまくいきません。文字列の途中のダブルクォートによってリージョンが終了し
てしまいます。文字列中のエスケープされたダブルクォートをスキップするように指定
する必要があります。それには "skip" キーワードを使います:
検索パターンの中ではバックスラッシュが特殊な文字として使われるので、連続した二
つのバックスラッシュが一つのバックスラッシュにマッチします。
マッチではなくリージョンを使うのはどんな場面でしょうか?主な違いは、マッチは一
つのパターンであり、そのパターン全体がマッチするということです。リージョンは
"start" パターンがマッチするとすぐに開始されます。"end" パターンが見つかるかど
うかは関係ありません。つまり、構文アイテムが "end" パターンにマッチすることに
依存している場合はリージョンは使えません。それが大丈夫なら、リージョンを定義す
る方が簡単な場合が多々あります。また、次の節でも述べるように、構文アイテムを入
れ子にする場合もリージョンが適しています。
==============================================================================
44.5 構文アイテムを入れ子にする
次のようなコメントがあります:
%Get input TODO: Skip white space
コメントを青色で強調表示し、その中の TODO を黄色の大きな字で強調表示してみま
しょう。それには、次のような構文グループを定義します:
一行目の "contained" 引数は、そのキーワードが他の構文アイテムの中にのみ出現す
ることを示しています。二行目の "contains=xTodo" は、その構文アイテムの中に
xTodo が出現することを示しています。結果、コメント全体は "xComment" にマッチし
て青色になり、その中の TODO は xTodo にマッチして黄色になります (xTodo に対す
る強調表示が設定してあるなら)。
入れ子の再帰
x 言語では波カッコでコードブロックを表現します。コードブロックの中にはさらに別
のコードブロックを入れることができます。これは次のように定義できます:
例えば、次のようなテキストがあった場合:
while i < b {
if a {
b = c;
}
}
まず、一行目の { で一つ目の xBlock が開始します。二行目には別の { があります。
そこは xBlock の中で、xBlock は自身を含むことができるので、二つ目の xBlock が
開始します。したがって、"b = c" の行は第二レベルの xBlock リージョンの中という
ことになります。次の行には } があり、これはリージョンの末尾を示すパターンに
マッチするので、これによって二つ目の xBlock が閉じます。この } は二つ目の
xBlock リージョンの中の文字なので、一つ目の xBlock リージョンからは隠されま
す。そして、最後の } によって一つ目の xBlock リージョンが閉じます。
末尾をキープする
次の二つの構文アイテムを見てみましょう:
% から行末までをコメントとして定義し、# から行末までをプリプロセッサー指令とし
て定義しています。プリプロセッサー行にはコメントを入れることができるので、プリ
プロセッサーの定義には "contains=xComment" 引数が指定されています。では、次の
ようなテキストで何が起こるか見てみましょう:
#define X = Y % Comment text
int foo = 1;
このテキストは、二行目も xPreProc として強調表示されます。プリプロセッサー指令
は行末で終わるものであり、そのために "end=/$/" と指定しました。何が間違っていた
のでしょうか?
問題は内包されたコメントにあります。コメントは % で始まり、行末で終わります。
コメントが終わるとプリプロセッサー構文に戻りますが、それは行末が処理された後な
ので、次の行も含まれてしまうのです。
この問題を回避し、内包された構文が改行を消費しないようにするには、"keepend" 引
数を使います。これで、行末への二重マッチに対応できます:
複数アイテムの内包
"contains=" 引数には「すべての構文アイテム」を指定することができます。例:
xList にはすべての構文アイテムが内包されます。「すべて」は自分自身を含みます
が、同じ位置のものは除外されます (無限ループを避けるため)。
一部のグループだけを除外するような指定もできます。つまり、指定したグループ以外
のグループを内包できます:
"TOP" を指定すると、"contained" 引数を持たないすべてのアイテムが対象になりま
す。"CONTAINED" を指定すると、"contained" 引数を持つアイテムだけが対象になりま
す。詳しくは :syn-contains を参照してください。
==============================================================================
44.6 グループの並び
x 言語には次のような形式のステートメントがあります:
if (condition) then
この三つのアイテムを別々に強調表示します。ただし、"(condition)" と "then" は他
の場所にも出現し、そこでは別の方法で強調表示されることもあります。次のように定
義します:
"nextgroup" 引数で、次に来るアイテムを指定します。これは (マッチするための) 必
須条件にはなりません。指定されたアイテムが見つからなかった場合は何も起こりませ
ん。例えば、次のテキストの場合:
if not (condition) then
"if" は xIf にマッチします。"not" は nextgroup に指定された xIfCondition に
マッチしません。したがって、"if" だけが強調表示されます。
"skipwhite" 引数を指定すると、次のアイテムとの間に空白 (スペースとタブ) をはさ
むことができます。同様に、"skipnl" を指定すれば、次のアイテムとの間に改行をは
さむことができ、"skipempty" を指定すれば、空行をはさむことができます。ただし、
"skipnl" は空行をスキップしないので注意してください。改行の後で何かにマッチす
る必要があります。
==============================================================================
44.7 その他の引数
マッチのグループ
リージョンは、リージョン全体が同じグループで強調表示されます。例えば、() で囲
まれたテキストを xInside グループで強調表示するため、次のように定義します:
このときに、カッコだけを別の方法で強調表示することを考えます。複雑な方法を使っ
て定義することもできますが、"matchgroup" 引数を使う方法もあります。
"matchgroup" を指定すると、リージョンの start と end の部分を別のハイライトグ
ループで表示できます (この例では xParen):
"matchgroup" 引数は、その引数より後ろに指定された start と end に対して適用さ
れます。上の例では start と end の両方が xParen で強調表示されます。end を
xParenEnd で強調表示する場合は次のようにします:
"matchgroup" を使うと、内包されたアイテムが start と end の部分にマッチしなく
なります。次の "transparent" の例題ではそれを利用しています。
透過
例えば C 言語のファイルで、"while" の後の () と、"for" の後の () を別の方法で
強調表示してみます。両方とも () を入れ子にできて、それが外側の () と同じ方法で
強調表示されるようにします。() の強調表示は ) がマッチしたところでストップしま
す。それには、例えば次のようにします:
cWhile と cFor には別の強調表示が使われます。cCondNest は両方に出現し、自身を
内包しているアイテムと同じハイライトグループで強調表示されます。"transparent"
引数によってこのような動作になります。
この例では、"matchgroup" 引数に自分自身のグループを指定しています。その理由
は、matchgroup を使うことで、内包されたアイテムが start の部分にマッチしないと
いう副作用が発生するからです。それを利用して cCondNest グループが "while" や
"for" の直後の ( にマッチしないようにしています。もし直後の ( にマッチしてしま
うと、cCondNest は ) までのすべてのテキストにマッチしてしまい、その後ろから
リージョンが再開することになってしまいます。matchgroup を指定することで、
cCondNest は start の後、つまり最初の ( より後でマッチするようになります。
オフセット
"if" の後ろにある ( と ) の間のテキストをリージョンとして定義します。ただし、
"if" と () 自体はリージョンに含めたくありません。そのような場合はオフセットを
使います。例:
start パターンには "ms=e+1" というオフセットが指定されています。"ms" は Match
Start という意味です。マッチの開始位置のオフセットを設定できます。通常は、パ
ターンがマッチした場所がマッチの開始位置になります。"e+1" はパターンがマッチし
たテキストの末尾からさらに一つ進んだ場所を示します。
end パターンには "me=s-1" というオフセットが指定されています。"me" は Match
End という意味です。"s-1" はパターンにマッチしたテキストの先頭から一つ戻った場
所を示します。例えば、次のテキストでは:
if (foo == bar)
"foo == bar" の部分だけが xCond で強調表示されます。
オフセットの詳細については :syn-pattern-offset を参照してください。
単一行
"oneline" 引数は、リージョンが複数行にまたがらないことを示します。例:
これは "if" で始まって "then" で終わるリージョンを定義しています。ただし、
"if" と "then" が同じ行にない場合はマッチしません。
Note:
"oneline" を使用した場合、end パターンが同じ行でマッチしない限り、リー
ジョンは開始されません。"oneline" がない場合は、end パターンがマッチす
る場所があるかどうかはチェックされません。その場合、たとえ end パター
ンにマッチする場所がなくても、リージョンは開始されます。
行の継続と継続の回避
さて、少し複雑になってきました。次はプリプロセッサー行を定義してみます。プリプ
ロセッサー行は行頭の # で始まり、行末まで続きます。行末が \ で終っていた場合は、
次の行まで継続します。それには、継続パターンにマッチする構文アイテムを内包する
ように指定します:
通常は xPreProc は単一行にマッチしますが、内包された xLineContinue によって次
の行まで継続するようになります。例えば、次のテキストは二行ともマッチします:
#define SPAM spam spam spam \
bacon and spam
これは期待した動作ですね。あるいは、内包されたパターンに "excludenl" を指定す
ることによって、リージョンを単一行に収めることもできます。例えば、xPreProc の
中で、行末に "end" があったときに、それを強調表示したいような場合に使います。
xPreProc が (xLineContinueのときのように) 次の行に継続しないようにするには、次
のように "excludenl" を使います:
"excludenl" はパターン指定の前に置いてください。"xLineContinue" には
"excludenl" が指定されていないので、最初の例と同様、マッチすることによって
xPreProc リージョンが拡張されます。
==============================================================================
44.8 クラスタ
構文ファイルを書いてみると、実にたくさんの構文グループを作成するということに気
づくと思います。必要なら、クラスタと呼ばれるものを定義して複数の構文グループを
ひとまとめにすることができます。
例えば、for ループ、if 文、while ループ、関数、などを持った言語があります。そ
れぞれは数値や識別子など、同じ構文要素を含むことができます。それを次のように定
義してみます:
同じ "contains=" を何度も書かなければなりません。内包されるアイテムを追加する
ときは、その変更を三回繰り返すことになります。クラスタを使って複数の構文グルー
プをひとまとめにすることで、このような指定が簡単になります。
上の三つのグループが内包している二つのアイテムをクラスタとして定義するには、次
のコマンドを使います:
クラスタは他の構文アイテムの中で使われます。使い方は普通の構文アイテムと同じで
す。名前の先頭に @ を付けてください。例の三つの構文アイテムは次のように定義で
きます:
クラスタに構文グループを追加するには "add" 引数を使います:
クラスタから構文グループを取り除くこともできます:
==============================================================================
44.9 他の構文ファイルをインクルードする
C++ 言語の構文は C 言語のスーパーセットです。構文ファイルを二つも書くのは避け
たいので、次のコマンドを使って、C++ 構文ファイルの中で C 構文ファイルを読み込
みます:
":runtime!" コマンドは 'runtimepath' の中からすべての "syntax/c.vim" を探しま
す。そして、C ファイルを開いたときと同様に、C++ における C の部分の構文が定義
されます。c.vim 構文ファイルを入れ替えていたり、拡張ファイルで構文アイテムを追
加していたりする場合は、それらも読み込まれます。
C の構文アイテムをロードしたら、C++ 特有の構文アイテムを定義します。例えば、C
にはないキーワードを定義します:
コマンドの動作は普通の構文ファイルのときと同じです。
次に、Perl 言語を考えてみましょう。Perl スクリプトは二つの異なる部分で構成され
ます。一つは POD 形式のドキュメントセクション、もう一つは Perl で書かれたプロ
グラムです。POD セクションは "=head" で始まり "=cut" で終わります。
POD 構文の定義を一つのファイルに書き、Perl 構文ファイルの中からそれを使いま
す。":syntax include" コマンドで構文ファイルを読み込むと、その中で定義されてい
る要素がクラスタに格納されます。Perl の場合、次のようなコマンドを使います:
Perl ファイルの中で "=head" が見つかると perlPOD リージョンが開始します。
perlPOD リージョンは @Pod クラスタを内包しています。リージョンの中では、
pod.vim 構文ファイルで定義されたトップレベルの構文アイテムがマッチします。
"=cut" が見つかるとリージョンは終了し、Perl ファイルの構文アイテムに戻ります。
":syntax include" コマンドで読み込まれたファイル内の ":syntax clear" コマンド
は適切に無視されます。さらに、"contains=ALL" のような引数は同じファイルの構文
アイテムだけが対象になります。呼び出し元の構文アイテムは対象になりません。
"<sfile>:p:h/" の部分は、カレントファイル名 (<sfile>) をフルパス (:p) に展開
し、その head (先端) (:h) を取り出しています。展開結果はファイルのディレクトリ
名になります。つまり、同じディレクトリの pod.vim がインクルードされます。
==============================================================================
44.10 シンクロナイズ (構文解析の同期)
例えばコンパイラなら話は簡単です。ファイルの先頭から開始して、順番に構文解析し
ていくだけです。しかし Vim では、ユーザーが編集している場所、つまりファイルの
途中から構文解析が開始されます。どのようにして適切な開始位置を決めているので
しょうか。
秘密は ":syntax sync" コマンドにあります。このコマンドを使って、構文解析の開始
位置を指定します。例えば、次のコマンドを使うと、C スタイルコメントの開始位置、
あるいは終了位置が後方検索され、その場所から構文ハイライトが開始されます:
引数を指定して動作を調整できます。"minlines" 引数には、後方検索で戻る最小の行
数を指定します。"maxlines" 引数には、検索される行数の上限を指定します。
例えば、画面の一番上に表示されている行から、最低でも 10 行前まで調べるようにす
るには、次のようにします:
最小の範囲内で見つからなかった場合は、適切な場所が見つかるまで、さらに戻って調
べます。ただし、500 行以上は戻りません。 ("maxlines" を大きくすると処理速度が
遅くなります。小さ過ぎるとシンクロナイズに失敗してしまいます。)
シンクロナイズは、スキップ可能な構文アイテムを指定することで、少し高速になりま
す。テキストを実際に表示するときだけ必要な構文アイテムを定義するときに
"display" 引数を指定してください。
デフォルトでは、検索されたコメントは Comment 構文グループで強調表示されます。
他の方法で強調表示したい場合は、使用したい構文グループを指定してください:
プログラミング言語が C スタイルコメントを持っていない場合は、他の方法でシンク
ロナイズします。最も簡単なのは、戻る行数を指定して、その場所から構文解析を試す
方法です。例えば、150 行前に戻って、そこから構文解析を開始するには、次のように
します:
"minlines" に大きな値を指定すると Vim の動作が遅くなります (特に上方にスクロー
ルする場合など)。
検索対象になる構文グループを指定することもできます:
{group-name} という構文グループが {pattern} にマッチした場所のすぐ後から開始す
るということを定義します。{sync-group-name} はシンクロナイズ定義の名前です。例
えば、sh スクリプトでは if 文を "if" で開始し、"fi" で閉じます:
if [ --f file.txt ] ; then
echo "File exists"
fi
この構文に対して "grouphere" を定義すると、次のようになります:
"groupthere" 引数を使ってグループの終端を示すパターンを指定します。例えば、
if/fi グループの終端は次のように定義できます:
この例では、NONE を指定して、パターンにマッチした場所が特定のリージョンの中で
はないこと、つまりは if ブロックの中ではないことを指定しています。
"grouphere" 引数と "groupthere" 引数を指定しないで、マッチやリージョンを定義す
ることもできます。そのようなグループはシンクロナイズのときにスキップされます。
例えば、次のように定義すると、{} で囲まれた範囲がスキップされます (他のシンク
ロナイズメソッドにマッチする場合でも):
シンクロナイズの詳細はリファレンスマニュアルの:syn-syncを参照してください。
==============================================================================
44.11 構文ファイルをインストールする
新しい構文ファイルを使用する準備ができたら、それを 'runtimepath' の "syntax"
ディレクトリにコピーしてください。Unix なら "~/.vim/syntax" です。
構文ファイルの名前はファイルタイプ名に ".vim" を付けた名前にします。したがっ
て、x 言語ならファイルのフルパスは次のようになります:
~/.vim/syntax/x.vim
さらに、ファイルタイプが認識されるように設定する必要があります。43.2 参照。
構文ファイルがうまく動作したら、それを他の Vim ユーザーが利用できるようにして
あげるといいでしょう。まず次のセクションを読んで、構文ファイルが他の環境でも動
作するようにしてください。そして、Vim のメンテナー <maintainer@vim.org> にメー
ルを送ってください。ファイルタイプの認識方法の説明もお願いします。よほどのこと
がない限り、Vim のバージョンアップに合わせて取り込まれます。
既存の構文ファイルを拡張する
上記は、完全に新しい構文ファイルを作成する場合の説明です。既存の構文ファイルを
使っていて、それに足りない構文アイテムがあるような場合には、それとは別のファイ
ルを使って構文アイテムを追加することができます。ファイルを別にすることで、Vim
をバージョンアップしたときに変更が失われてしまうのを防止します。
syntax コマンドを自分のファイルに書きます。できる限り既存の構文グループの名前
を使ってください。例えば、C 構文ファイルに新しい変数タイプを追加するには、次の
ように書きます:
これを、元の構文ファイルと同じ名前で保存します。この場合なら "c.vim" です。そ
のファイルを 'runtimepath' の最後の方にあるディレクトリに置きます。そうするこ
とで、元の構文ファイルよりも後に読み込ませます。Unix なら次の場所に保存します:
~/.vim/after/syntax/c.vim
==============================================================================
44.12 ポータブルな構文ファイル
すべての Vim ユーザーが構文ファイルを共有できれば素晴らしいと思いませんか?そ
のためには、構文ファイルはいくつかのガイドラインに従っている必要があります。
ファイルの先頭にヘッダーを書いてください。構文ファイルの用途、メンテナー、最終
更新日を書きます。詳細な変更履歴は必要ありません(ほとんどの人はそれを読みませ
ん)。
例:
他の構文ファイルと同じレイアウトを使ってください。既存の構文ファイルを参考にす
ると時間を節約できます。
構文ファイルには分かりやすい名前を付けます。小文字と数字だけを使ってください。
名前は多くの場所で使うので長くなり過ぎないようにします (構文ファイルの名前
("name.vim")、'filetype'、b:current_syntax、構文グループの接頭辞 (nameType、
nameStatement、nameString、etc) などで使います)。
最初に "b:current_syntax" をチェックします。これが定義済みなら、他の構文ファイ
ルが 'runtimepath' の前の方でロードされたということです:
ファイルの最後で "b:current_syntax" に構文の名前を設定します。ファイルをインク
ルードしている場合、そのファイルの中でも "b:current_syntax" が設定されるので注
意してください。複数のファイルをインクルードする場合には、"b:current_syntax"
をリセットする必要があるかもしれません。
ユーザー設定を変更しないでください。'tabstop' や 'expandtab' などの設定を変更
してはいけません。そのような設定はファイルタイププラグインの仕事です。
マップや短縮入力を定義しないでください。'iskeyword' だけは、キーワードの識別に
どうしても必要なら、設定しても構いません。
ユーザーが好みの色を選択できるように、強調表示されるグループの名前に標準とは違
う名前を付けます。そして、それらを標準のハイライトグループにリンクします。そう
すればどのカラースキームでも適切に強調表示できます。標準以外のハイライトグルー
プを使ってしまうと、カラースキームによっては正しく強調表示されません。また、
ユーザーの環境によって背景色が違ったり、色数が 8 色しかない場合もあるので覚え
ておいてください。
ハイライトグループをリンクするには "hi def link" を使います。そうすることで、
ユーザーはあなたの構文ファイルがロードされる前の段階で他のハイライトグループを
選択できます。例:
シンクロナイズで使用しない構文アイテムには "display" 引数を付けてください。上
方向へのスクロールや CTRL-L の動作が早くなります。
==============================================================================
次章: usr_45.txt 言語を選択する
Copyright: see manual-copyright vim:tw=78:ts=8:noet:ft=help:norl:
VIM USER MANUAL - by Bram Moolenaar
構文ファイルを作成する
Vim は 200 種類以上ものファイルを強調表示できます。強調表示されないファイルを
見つけた場合は、本章を読んで、ファイルを強調表示する方法を調べてください。リ
ファレンスマニュアルの :syn-define も参照してください。
44.1 基本的な syntax コマンド
44.2 キーワード
44.3 マッチ
44.4 リージョン
44.5 構文アイテムを入れ子にする
44.6 グループの並び
44.7 その他の引数
44.8 クラスタ
44.9 他の構文ファイルをインクルードする
44.10 シンクロナイズ
44.11 構文ファイルをインストールする
44.12 ポータブルな文法定義ファイル
次章: usr_45.txt 言語を選択する
前章: usr_43.txt ファイルタイプを使う
目次: usr_toc.txt
==============================================================================
44.1 基本的な syntax コマンド
既存の構文ファイルを土台にすることで多くの時間を節約できます。望みのものに近い
言語の構文ファイルを $VIMRUNTIME/syntax から探してください。それらのファイルを
見れば、構文ファイルの基本的な構造がわかると思います。内容を理解するには本章を
読んでください。
基本的なことから説明します。構文定義を開始する前に、古い定義をクリアする必要が
あります:
:syntax clear
最終的な構文ファイルではこのコマンドは必要ありませんが、いろいろと試したいとき
には便利です。
本章の説明はかなり簡略化されています。構文ファイルを書いて、それを他人に使って
もらう場合は、本章を最後まで読んで詳細を理解してください。
定義された構文アイテムを一覧表示する
現在定義されている構文アイテムを表示するには、次のコマンドを使います:
:syntax
実際に定義されている構文アイテムを確認することができます。新しい構文ファイルを
作っていて、いろいろと試しているときに便利です。また、それぞれの構文アイテム
は、実際の表示と同じ色で表示されるので、何がどうなっているかも確認できます。
特定の構文グループのアイテムを一覧表示するには次のようにします:
:syntax list {group-name}
これはクラスタ (44.8参照) を一覧表示することもできます。その場合は名前に @
を付けてください。
大文字と小文字の区別
Pascal などの言語は大文字と小文字を区別しません。C などの言語は大文字と小文字
を区別します。次のコマンドで区別するかしないかを指定できます:
:syntax case match (大文字/小文字を区別する)
:syntax case ignore (大文字/小文字を区別しない)
:syntax case ignore (大文字/小文字を区別しない)
"match" を指定すると大文字と小文字は区別されます。その場合、"int" と "Int" と
"INT" はそれぞれ違うものになります。"ignore" を指定した場合は、"Procedure" と
"PROCEDURE" と "procedure" は同じ扱いになります。
":syntax case" コマンドは構文ファイルのどこにでも書くことができ、それ以降の構
文定義に作用します。ほとんどの場合、":syntax case" コマンドは構文ファイルに一
つだけ書きますが、大文字と小文字を区別する要素と区別しない要素を両方もつような
特殊な言語の場合には、ファイルのいたるところで ":syntax case" コマンドを書くこ
ともできます。
==============================================================================
44.2 キーワード
最も基本的な構文要素はキーワードです。次のように定義します:
:syntax keyword {group} {keyword} ...
{group} は構文グループの名前です。":highlight" コマンドを使うことで {group} に
色を割り当てることができます。{keyword} は実際のキーワードです。いくつか例を示
します:
:syntax keyword xType int long char
:syntax keyword xStatement if then else endif
:syntax keyword xStatement if then else endif
"xType" と "xStatement" がグループ名です。習慣的に、グループ名の先頭にはファイ
ルタイプ名が付けられます。この例では x 言語 (そういう言語があるのではなく単に
eXample の x) の構文を定義しています。例えば "csh" スクリプト用の構文ファイル
なら "cshType" という名前になります。つまり、'filetype' の値と同じものを先頭に
付けます。
この例では "int" と "long" と "char" が同じ方法で強調表示され、"if" と "then"
と "else" と "endif" が別の同じ方法で強調表示されます。次に、x グループ名と
Vim の標準名を関連付ける必要があります。次のようにします:
:highlight link xType Type
:highlight link xStatement Statement
:highlight link xStatement Statement
"xType" を "Type" で強調表示し、"xStatement" を "Statement" で強調表示します。
標準名については group-name を参照してください。
特殊なキーワード
キーワードとして使われる文字は 'iskeyword' オプションに指定されていなければな
りません。それ以外の文字を使った場合、その単語は決してマッチしません。Vim はそ
のことについて警告メッセージを出しません。
例題の x 言語は '-' 文字をキーワードとして使えます。それは次のように設定しま
す:
:setlocal iskeyword+=-
:syntax keyword xStatement when-not
:syntax keyword xStatement when-not
":setlocal" コマンドを使って、カレントバッファだけ 'iskeyword' を変更していま
す。この設定によって "w" や "*" などのコマンドの動作も変更されます。動作を変更
したくない場合は、キーワードではなくマッチを使ってください(次節で説明します)。
x 言語では短縮形も使えます。例えば、"next" は "n"、"ne"、"nex" に短縮できま
す。次のコマンドでそれを定義できます:
:syntax keyword xStatement n[ext]
これは "nextone" にはマッチしません。キーワードは常に単語全体にのみマッチしま
す。
==============================================================================
44.3 マッチ
もう少し複雑なものを定義してみましょう。普通の識別子にマッチさせるため、マッチ
構文アイテムを定義します。次の例は、すべての文字が小文字の単語にマッチします:
:syntax match xIdentifier /\<\l\+\>/
Note:
キーワードは他の構文アイテムより優先されます。"if" や "then" などの
キーワード (上述の ":syntax keyword" コマンドで定義したもの) は、
xIdentifier にもマッチしますが、キーワードとして扱われます。
最後の部分はパターンです。これは検索で使用するものと同じです。// を使ってパ
ターンを囲みます (":substitute" コマンドと同じ)。+ や " など、他の文字を使うこ
ともできます。
次はコメント用のマッチを定義してみます。x 言語では "#" から行末までがコメント
になります:
:syntax match xComment /#.*/
すべての検索パターンが使えるので、マッチを使うことで非常に複雑なものを強調表示
できます。検索パターンについては pattern を参照してください。
==============================================================================
44.4 リージョン
例題の x 言語では、文字列をダブルクォートで囲みます。文字列を強調表示するため
にリージョン (領域) を定義します。それにはリージョンの開始 (ダブルクォート) と
リージョンの終了 (ダブルクォート) が必要です。定義は次のようになります:
:syntax region xString start=/"/ end=/"/
"start" と "end" に指定したパターンは、リージョンの開始と終了を探すために使用
されます。しかし次のような文字列があったらどうなるでしょうか?
"A string with a double quote (\") in it"
これはうまくいきません。文字列の途中のダブルクォートによってリージョンが終了し
てしまいます。文字列中のエスケープされたダブルクォートをスキップするように指定
する必要があります。それには "skip" キーワードを使います:
:syntax region xString start=/"/ skip=/\\"/ end=/"/
検索パターンの中ではバックスラッシュが特殊な文字として使われるので、連続した二
つのバックスラッシュが一つのバックスラッシュにマッチします。
マッチではなくリージョンを使うのはどんな場面でしょうか?主な違いは、マッチは一
つのパターンであり、そのパターン全体がマッチするということです。リージョンは
"start" パターンがマッチするとすぐに開始されます。"end" パターンが見つかるかど
うかは関係ありません。つまり、構文アイテムが "end" パターンにマッチすることに
依存している場合はリージョンは使えません。それが大丈夫なら、リージョンを定義す
る方が簡単な場合が多々あります。また、次の節でも述べるように、構文アイテムを入
れ子にする場合もリージョンが適しています。
==============================================================================
44.5 構文アイテムを入れ子にする
次のようなコメントがあります:
%Get input TODO: Skip white space
コメントを青色で強調表示し、その中の TODO を黄色の大きな字で強調表示してみま
しょう。それには、次のような構文グループを定義します:
:syntax keyword xTodo TODO contained
:syntax match xComment /%.*/ contains=xTodo
:syntax match xComment /%.*/ contains=xTodo
一行目の "contained" 引数は、そのキーワードが他の構文アイテムの中にのみ出現す
ることを示しています。二行目の "contains=xTodo" は、その構文アイテムの中に
xTodo が出現することを示しています。結果、コメント全体は "xComment" にマッチし
て青色になり、その中の TODO は xTodo にマッチして黄色になります (xTodo に対す
る強調表示が設定してあるなら)。
入れ子の再帰
x 言語では波カッコでコードブロックを表現します。コードブロックの中にはさらに別
のコードブロックを入れることができます。これは次のように定義できます:
:syntax region xBlock start=/{/ end=/}/ contains=xBlock
例えば、次のようなテキストがあった場合:
while i < b {
if a {
b = c;
}
}
まず、一行目の { で一つ目の xBlock が開始します。二行目には別の { があります。
そこは xBlock の中で、xBlock は自身を含むことができるので、二つ目の xBlock が
開始します。したがって、"b = c" の行は第二レベルの xBlock リージョンの中という
ことになります。次の行には } があり、これはリージョンの末尾を示すパターンに
マッチするので、これによって二つ目の xBlock が閉じます。この } は二つ目の
xBlock リージョンの中の文字なので、一つ目の xBlock リージョンからは隠されま
す。そして、最後の } によって一つ目の xBlock リージョンが閉じます。
末尾をキープする
次の二つの構文アイテムを見てみましょう:
:syntax region xComment start=/%/ end=/$/ contained
:syntax region xPreProc start=/#/ end=/$/ contains=xComment
:syntax region xPreProc start=/#/ end=/$/ contains=xComment
% から行末までをコメントとして定義し、# から行末までをプリプロセッサー指令とし
て定義しています。プリプロセッサー行にはコメントを入れることができるので、プリ
プロセッサーの定義には "contains=xComment" 引数が指定されています。では、次の
ようなテキストで何が起こるか見てみましょう:
#define X = Y % Comment text
int foo = 1;
このテキストは、二行目も xPreProc として強調表示されます。プリプロセッサー指令
は行末で終わるものであり、そのために "end=/$/" と指定しました。何が間違っていた
のでしょうか?
問題は内包されたコメントにあります。コメントは % で始まり、行末で終わります。
コメントが終わるとプリプロセッサー構文に戻りますが、それは行末が処理された後な
ので、次の行も含まれてしまうのです。
この問題を回避し、内包された構文が改行を消費しないようにするには、"keepend" 引
数を使います。これで、行末への二重マッチに対応できます:
:syntax region xComment start=/%/ end=/$/ contained
:syntax region xPreProc start=/#/ end=/$/ contains=xComment keepend
:syntax region xPreProc start=/#/ end=/$/ contains=xComment keepend
複数アイテムの内包
"contains=" 引数には「すべての構文アイテム」を指定することができます。例:
:syntax region xList start=/\[/ end=/\]/ contains=ALL
xList にはすべての構文アイテムが内包されます。「すべて」は自分自身を含みます
が、同じ位置のものは除外されます (無限ループを避けるため)。
一部のグループだけを除外するような指定もできます。つまり、指定したグループ以外
のグループを内包できます:
:syntax region xList start=/\[/ end=/\]/ contains=ALLBUT,xString
"TOP" を指定すると、"contained" 引数を持たないすべてのアイテムが対象になりま
す。"CONTAINED" を指定すると、"contained" 引数を持つアイテムだけが対象になりま
す。詳しくは :syn-contains を参照してください。
==============================================================================
44.6 グループの並び
x 言語には次のような形式のステートメントがあります:
if (condition) then
この三つのアイテムを別々に強調表示します。ただし、"(condition)" と "then" は他
の場所にも出現し、そこでは別の方法で強調表示されることもあります。次のように定
義します:
:syntax match xIf /if/ nextgroup=xIfCondition skipwhite
:syntax match xIfCondition /([^)]*)/ contained nextgroup=xThen skipwhite
:syntax match xThen /then/ contained
:syntax match xIfCondition /([^)]*)/ contained nextgroup=xThen skipwhite
:syntax match xThen /then/ contained
"nextgroup" 引数で、次に来るアイテムを指定します。これは (マッチするための) 必
須条件にはなりません。指定されたアイテムが見つからなかった場合は何も起こりませ
ん。例えば、次のテキストの場合:
if not (condition) then
"if" は xIf にマッチします。"not" は nextgroup に指定された xIfCondition に
マッチしません。したがって、"if" だけが強調表示されます。
"skipwhite" 引数を指定すると、次のアイテムとの間に空白 (スペースとタブ) をはさ
むことができます。同様に、"skipnl" を指定すれば、次のアイテムとの間に改行をは
さむことができ、"skipempty" を指定すれば、空行をはさむことができます。ただし、
"skipnl" は空行をスキップしないので注意してください。改行の後で何かにマッチす
る必要があります。
==============================================================================
44.7 その他の引数
マッチのグループ
リージョンは、リージョン全体が同じグループで強調表示されます。例えば、() で囲
まれたテキストを xInside グループで強調表示するため、次のように定義します:
:syntax region xInside start=/(/ end=/)/
このときに、カッコだけを別の方法で強調表示することを考えます。複雑な方法を使っ
て定義することもできますが、"matchgroup" 引数を使う方法もあります。
"matchgroup" を指定すると、リージョンの start と end の部分を別のハイライトグ
ループで表示できます (この例では xParen):
:syntax region xInside matchgroup=xParen start=/(/ end=/)/
"matchgroup" 引数は、その引数より後ろに指定された start と end に対して適用さ
れます。上の例では start と end の両方が xParen で強調表示されます。end を
xParenEnd で強調表示する場合は次のようにします:
:syntax region xInside matchgroup=xParen start=/(/
\ matchgroup=xParenEnd end=/)/
\ matchgroup=xParenEnd end=/)/
"matchgroup" を使うと、内包されたアイテムが start と end の部分にマッチしなく
なります。次の "transparent" の例題ではそれを利用しています。
透過
例えば C 言語のファイルで、"while" の後の () と、"for" の後の () を別の方法で
強調表示してみます。両方とも () を入れ子にできて、それが外側の () と同じ方法で
強調表示されるようにします。() の強調表示は ) がマッチしたところでストップしま
す。それには、例えば次のようにします:
:syntax region cWhile matchgroup=cWhile start=/while\s*(/ end=/)/
\ contains=cCondNest
:syntax region cFor matchgroup=cFor start=/for\s*(/ end=/)/
\ contains=cCondNest
:syntax region cCondNest start=/(/ end=/)/ contained transparent
\ contains=cCondNest
:syntax region cFor matchgroup=cFor start=/for\s*(/ end=/)/
\ contains=cCondNest
:syntax region cCondNest start=/(/ end=/)/ contained transparent
cWhile と cFor には別の強調表示が使われます。cCondNest は両方に出現し、自身を
内包しているアイテムと同じハイライトグループで強調表示されます。"transparent"
引数によってこのような動作になります。
この例では、"matchgroup" 引数に自分自身のグループを指定しています。その理由
は、matchgroup を使うことで、内包されたアイテムが start の部分にマッチしないと
いう副作用が発生するからです。それを利用して cCondNest グループが "while" や
"for" の直後の ( にマッチしないようにしています。もし直後の ( にマッチしてしま
うと、cCondNest は ) までのすべてのテキストにマッチしてしまい、その後ろから
リージョンが再開することになってしまいます。matchgroup を指定することで、
cCondNest は start の後、つまり最初の ( より後でマッチするようになります。
オフセット
"if" の後ろにある ( と ) の間のテキストをリージョンとして定義します。ただし、
"if" と () 自体はリージョンに含めたくありません。そのような場合はオフセットを
使います。例:
:syntax region xCond start=/if\s*(/ms=e+1 end=/)/me=s-1
start パターンには "ms=e+1" というオフセットが指定されています。"ms" は Match
Start という意味です。マッチの開始位置のオフセットを設定できます。通常は、パ
ターンがマッチした場所がマッチの開始位置になります。"e+1" はパターンがマッチし
たテキストの末尾からさらに一つ進んだ場所を示します。
end パターンには "me=s-1" というオフセットが指定されています。"me" は Match
End という意味です。"s-1" はパターンにマッチしたテキストの先頭から一つ戻った場
所を示します。例えば、次のテキストでは:
if (foo == bar)
"foo == bar" の部分だけが xCond で強調表示されます。
オフセットの詳細については :syn-pattern-offset を参照してください。
単一行
"oneline" 引数は、リージョンが複数行にまたがらないことを示します。例:
:syntax region xIfThen start=/if/ end=/then/ oneline
これは "if" で始まって "then" で終わるリージョンを定義しています。ただし、
"if" と "then" が同じ行にない場合はマッチしません。
Note:
"oneline" を使用した場合、end パターンが同じ行でマッチしない限り、リー
ジョンは開始されません。"oneline" がない場合は、end パターンがマッチす
る場所があるかどうかはチェックされません。その場合、たとえ end パター
ンにマッチする場所がなくても、リージョンは開始されます。
行の継続と継続の回避
さて、少し複雑になってきました。次はプリプロセッサー行を定義してみます。プリプ
ロセッサー行は行頭の # で始まり、行末まで続きます。行末が \ で終っていた場合は、
次の行まで継続します。それには、継続パターンにマッチする構文アイテムを内包する
ように指定します:
:syntax region xPreProc start=/^#/ end=/$/ contains=xLineContinue
:syntax match xLineContinue "\\$" contained
:syntax match xLineContinue "\\$" contained
通常は xPreProc は単一行にマッチしますが、内包された xLineContinue によって次
の行まで継続するようになります。例えば、次のテキストは二行ともマッチします:
#define SPAM spam spam spam \
bacon and spam
これは期待した動作ですね。あるいは、内包されたパターンに "excludenl" を指定す
ることによって、リージョンを単一行に収めることもできます。例えば、xPreProc の
中で、行末に "end" があったときに、それを強調表示したいような場合に使います。
xPreProc が (xLineContinueのときのように) 次の行に継続しないようにするには、次
のように "excludenl" を使います:
:syntax region xPreProc start=/^#/ end=/$/
\ contains=xLineContinue,xPreProcEnd
:syntax match xPreProcEnd excludenl /end$/ contained
:syntax match xLineContinue "\\$" contained
\ contains=xLineContinue,xPreProcEnd
:syntax match xPreProcEnd excludenl /end$/ contained
:syntax match xLineContinue "\\$" contained
"excludenl" はパターン指定の前に置いてください。"xLineContinue" には
"excludenl" が指定されていないので、最初の例と同様、マッチすることによって
xPreProc リージョンが拡張されます。
==============================================================================
44.8 クラスタ
構文ファイルを書いてみると、実にたくさんの構文グループを作成するということに気
づくと思います。必要なら、クラスタと呼ばれるものを定義して複数の構文グループを
ひとまとめにすることができます。
例えば、for ループ、if 文、while ループ、関数、などを持った言語があります。そ
れぞれは数値や識別子など、同じ構文要素を含むことができます。それを次のように定
義してみます:
:syntax match xFor /^for.*/ contains=xNumber,xIdent
:syntax match xIf /^if.*/ contains=xNumber,xIdent
:syntax match xWhile /^while.*/ contains=xNumber,xIdent
:syntax match xIf /^if.*/ contains=xNumber,xIdent
:syntax match xWhile /^while.*/ contains=xNumber,xIdent
同じ "contains=" を何度も書かなければなりません。内包されるアイテムを追加する
ときは、その変更を三回繰り返すことになります。クラスタを使って複数の構文グルー
プをひとまとめにすることで、このような指定が簡単になります。
上の三つのグループが内包している二つのアイテムをクラスタとして定義するには、次
のコマンドを使います:
:syntax cluster xState contains=xNumber,xIdent
クラスタは他の構文アイテムの中で使われます。使い方は普通の構文アイテムと同じで
す。名前の先頭に @ を付けてください。例の三つの構文アイテムは次のように定義で
きます:
:syntax match xFor /^for.*/ contains=@xState
:syntax match xIf /^if.*/ contains=@xState
:syntax match xWhile /^while.*/ contains=@xState
:syntax match xIf /^if.*/ contains=@xState
:syntax match xWhile /^while.*/ contains=@xState
クラスタに構文グループを追加するには "add" 引数を使います:
:syntax cluster xState add=xString
クラスタから構文グループを取り除くこともできます:
:syntax cluster xState remove=xNumber
==============================================================================
44.9 他の構文ファイルをインクルードする
C++ 言語の構文は C 言語のスーパーセットです。構文ファイルを二つも書くのは避け
たいので、次のコマンドを使って、C++ 構文ファイルの中で C 構文ファイルを読み込
みます:
:runtime! syntax/c.vim
":runtime!" コマンドは 'runtimepath' の中からすべての "syntax/c.vim" を探しま
す。そして、C ファイルを開いたときと同様に、C++ における C の部分の構文が定義
されます。c.vim 構文ファイルを入れ替えていたり、拡張ファイルで構文アイテムを追
加していたりする場合は、それらも読み込まれます。
C の構文アイテムをロードしたら、C++ 特有の構文アイテムを定義します。例えば、C
にはないキーワードを定義します:
:syntax keyword cppStatement new delete this friend using
コマンドの動作は普通の構文ファイルのときと同じです。
次に、Perl 言語を考えてみましょう。Perl スクリプトは二つの異なる部分で構成され
ます。一つは POD 形式のドキュメントセクション、もう一つは Perl で書かれたプロ
グラムです。POD セクションは "=head" で始まり "=cut" で終わります。
POD 構文の定義を一つのファイルに書き、Perl 構文ファイルの中からそれを使いま
す。":syntax include" コマンドで構文ファイルを読み込むと、その中で定義されてい
る要素がクラスタに格納されます。Perl の場合、次のようなコマンドを使います:
:syntax include @Pod <sfile>:p:h/pod.vim
:syntax region perlPOD start=/^=head/ end=/^=cut/ contains=@Pod
:syntax region perlPOD start=/^=head/ end=/^=cut/ contains=@Pod
Perl ファイルの中で "=head" が見つかると perlPOD リージョンが開始します。
perlPOD リージョンは @Pod クラスタを内包しています。リージョンの中では、
pod.vim 構文ファイルで定義されたトップレベルの構文アイテムがマッチします。
"=cut" が見つかるとリージョンは終了し、Perl ファイルの構文アイテムに戻ります。
":syntax include" コマンドで読み込まれたファイル内の ":syntax clear" コマンド
は適切に無視されます。さらに、"contains=ALL" のような引数は同じファイルの構文
アイテムだけが対象になります。呼び出し元の構文アイテムは対象になりません。
"<sfile>:p:h/" の部分は、カレントファイル名 (<sfile>) をフルパス (:p) に展開
し、その head (先端) (:h) を取り出しています。展開結果はファイルのディレクトリ
名になります。つまり、同じディレクトリの pod.vim がインクルードされます。
==============================================================================
44.10 シンクロナイズ (構文解析の同期)
例えばコンパイラなら話は簡単です。ファイルの先頭から開始して、順番に構文解析し
ていくだけです。しかし Vim では、ユーザーが編集している場所、つまりファイルの
途中から構文解析が開始されます。どのようにして適切な開始位置を決めているので
しょうか。
秘密は ":syntax sync" コマンドにあります。このコマンドを使って、構文解析の開始
位置を指定します。例えば、次のコマンドを使うと、C スタイルコメントの開始位置、
あるいは終了位置が後方検索され、その場所から構文ハイライトが開始されます:
:syntax sync ccomment
引数を指定して動作を調整できます。"minlines" 引数には、後方検索で戻る最小の行
数を指定します。"maxlines" 引数には、検索される行数の上限を指定します。
例えば、画面の一番上に表示されている行から、最低でも 10 行前まで調べるようにす
るには、次のようにします:
:syntax sync ccomment minlines=10 maxlines=500
最小の範囲内で見つからなかった場合は、適切な場所が見つかるまで、さらに戻って調
べます。ただし、500 行以上は戻りません。 ("maxlines" を大きくすると処理速度が
遅くなります。小さ過ぎるとシンクロナイズに失敗してしまいます。)
シンクロナイズは、スキップ可能な構文アイテムを指定することで、少し高速になりま
す。テキストを実際に表示するときだけ必要な構文アイテムを定義するときに
"display" 引数を指定してください。
デフォルトでは、検索されたコメントは Comment 構文グループで強調表示されます。
他の方法で強調表示したい場合は、使用したい構文グループを指定してください:
:syntax sync ccomment xAltComment
プログラミング言語が C スタイルコメントを持っていない場合は、他の方法でシンク
ロナイズします。最も簡単なのは、戻る行数を指定して、その場所から構文解析を試す
方法です。例えば、150 行前に戻って、そこから構文解析を開始するには、次のように
します:
:syntax sync minlines=150
"minlines" に大きな値を指定すると Vim の動作が遅くなります (特に上方にスクロー
ルする場合など)。
検索対象になる構文グループを指定することもできます:
:syntax sync match {sync-group-name}
\ grouphere {group-name} {pattern}
\ grouphere {group-name} {pattern}
{group-name} という構文グループが {pattern} にマッチした場所のすぐ後から開始す
るということを定義します。{sync-group-name} はシンクロナイズ定義の名前です。例
えば、sh スクリプトでは if 文を "if" で開始し、"fi" で閉じます:
if [ --f file.txt ] ; then
echo "File exists"
fi
この構文に対して "grouphere" を定義すると、次のようになります:
:syntax sync match shIfSync grouphere shIf "\<if\>"
"groupthere" 引数を使ってグループの終端を示すパターンを指定します。例えば、
if/fi グループの終端は次のように定義できます:
:syntax sync match shIfSync groupthere NONE "\<fi\>"
この例では、NONE を指定して、パターンにマッチした場所が特定のリージョンの中で
はないこと、つまりは if ブロックの中ではないことを指定しています。
"grouphere" 引数と "groupthere" 引数を指定しないで、マッチやリージョンを定義す
ることもできます。そのようなグループはシンクロナイズのときにスキップされます。
例えば、次のように定義すると、{} で囲まれた範囲がスキップされます (他のシンク
ロナイズメソッドにマッチする場合でも):
:syntax sync match xSpecial /{.*}/
シンクロナイズの詳細はリファレンスマニュアルの:syn-syncを参照してください。
==============================================================================
44.11 構文ファイルをインストールする
新しい構文ファイルを使用する準備ができたら、それを 'runtimepath' の "syntax"
ディレクトリにコピーしてください。Unix なら "~/.vim/syntax" です。
構文ファイルの名前はファイルタイプ名に ".vim" を付けた名前にします。したがっ
て、x 言語ならファイルのフルパスは次のようになります:
~/.vim/syntax/x.vim
さらに、ファイルタイプが認識されるように設定する必要があります。43.2 参照。
構文ファイルがうまく動作したら、それを他の Vim ユーザーが利用できるようにして
あげるといいでしょう。まず次のセクションを読んで、構文ファイルが他の環境でも動
作するようにしてください。そして、Vim のメンテナー <maintainer@vim.org> にメー
ルを送ってください。ファイルタイプの認識方法の説明もお願いします。よほどのこと
がない限り、Vim のバージョンアップに合わせて取り込まれます。
既存の構文ファイルを拡張する
上記は、完全に新しい構文ファイルを作成する場合の説明です。既存の構文ファイルを
使っていて、それに足りない構文アイテムがあるような場合には、それとは別のファイ
ルを使って構文アイテムを追加することができます。ファイルを別にすることで、Vim
をバージョンアップしたときに変更が失われてしまうのを防止します。
syntax コマンドを自分のファイルに書きます。できる限り既存の構文グループの名前
を使ってください。例えば、C 構文ファイルに新しい変数タイプを追加するには、次の
ように書きます:
:syntax keyword cType off_t uint
これを、元の構文ファイルと同じ名前で保存します。この場合なら "c.vim" です。そ
のファイルを 'runtimepath' の最後の方にあるディレクトリに置きます。そうするこ
とで、元の構文ファイルよりも後に読み込ませます。Unix なら次の場所に保存します:
~/.vim/after/syntax/c.vim
==============================================================================
44.12 ポータブルな構文ファイル
すべての Vim ユーザーが構文ファイルを共有できれば素晴らしいと思いませんか?そ
のためには、構文ファイルはいくつかのガイドラインに従っている必要があります。
ファイルの先頭にヘッダーを書いてください。構文ファイルの用途、メンテナー、最終
更新日を書きます。詳細な変更履歴は必要ありません(ほとんどの人はそれを読みませ
ん)。
例:
" Vim syntax file
" Language: C
" Maintainer: Bram Moolenaar <Bram@vim.org>
" Last Change: 2001 Jun 18
" Remark: Included by the C++ syntax.
" Language: C
" Maintainer: Bram Moolenaar <Bram@vim.org>
" Last Change: 2001 Jun 18
" Remark: Included by the C++ syntax.
他の構文ファイルと同じレイアウトを使ってください。既存の構文ファイルを参考にす
ると時間を節約できます。
構文ファイルには分かりやすい名前を付けます。小文字と数字だけを使ってください。
名前は多くの場所で使うので長くなり過ぎないようにします (構文ファイルの名前
("name.vim")、'filetype'、b:current_syntax、構文グループの接頭辞 (nameType、
nameStatement、nameString、etc) などで使います)。
最初に "b:current_syntax" をチェックします。これが定義済みなら、他の構文ファイ
ルが 'runtimepath' の前の方でロードされたということです:
if exists("b:current_syntax")
finish
endif
finish
endif
ファイルの最後で "b:current_syntax" に構文の名前を設定します。ファイルをインク
ルードしている場合、そのファイルの中でも "b:current_syntax" が設定されるので注
意してください。複数のファイルをインクルードする場合には、"b:current_syntax"
をリセットする必要があるかもしれません。
ユーザー設定を変更しないでください。'tabstop' や 'expandtab' などの設定を変更
してはいけません。そのような設定はファイルタイププラグインの仕事です。
マップや短縮入力を定義しないでください。'iskeyword' だけは、キーワードの識別に
どうしても必要なら、設定しても構いません。
ユーザーが好みの色を選択できるように、強調表示されるグループの名前に標準とは違
う名前を付けます。そして、それらを標準のハイライトグループにリンクします。そう
すればどのカラースキームでも適切に強調表示できます。標準以外のハイライトグルー
プを使ってしまうと、カラースキームによっては正しく強調表示されません。また、
ユーザーの環境によって背景色が違ったり、色数が 8 色しかない場合もあるので覚え
ておいてください。
ハイライトグループをリンクするには "hi def link" を使います。そうすることで、
ユーザーはあなたの構文ファイルがロードされる前の段階で他のハイライトグループを
選択できます。例:
hi def link nameString String
hi def link nameNumber Number
hi def link nameCommand Statement
... etc ...
hi def link nameNumber Number
hi def link nameCommand Statement
... etc ...
シンクロナイズで使用しない構文アイテムには "display" 引数を付けてください。上
方向へのスクロールや CTRL-L の動作が早くなります。
==============================================================================
次章: usr_45.txt 言語を選択する
Copyright: see manual-copyright vim:tw=78:ts=8:noet:ft=help:norl: