CodeMirrorのModeを作る

CodeMirror 用の独自の Mode の作り方を紹介します。この記事では、SimpleMode を使わない方法を紹介します。


大枠

CodeMirror.defineMode
メソッドに、モード名と、token 関数をメンバに持つオブジェクトを返す関数を渡すとモードが定義できます。CodeMirror についているモードのソースには、CommonJS や AMD モジュール用のコードも付いていますが、この辺りはなくても大丈夫でした。

返すオブジェクトに startState を含めると、字句解析中の状態を保持するためのオブジェクトを設定できます。この関数で返したオブジェクトが、token 関数の第二引数に渡されるため、そちらのオブジェクトに値を設定することで、状態の保存なども可能になります。

コード1: 空のモード

token 関数

token 関数では、第一引数の stream オブジェクトからから文字を読み取り、渡されたところから読み進めたところまでのトークンの種類を文字列で返します。返すトークンの種類は任意の文字列で良いようで、トークンが設定された部分には、スタイルシートの

cm-トークンの種類
クラスが適用されます。null を返すと何も設定されないようです。また、stream オブジェクトから一文字も読み出さずに関数を抜けてしまうと、エラーになります。

stream オブジェクトの詳細は公式ドキュメントをご覧いただければと思いますが、ここでは、よく使うメソッドをまとめておきます。

表1: stream のよく使うメソッド
メソッド 動作
peek() → string ストリームを進めずに次の一文字を読み取ります。終端の場合 null を返します。
next() → string 次の一文字を読み取り、ストリームを 1 文字進めます。終端の場合 null を返します。
sol() → boolean 行頭の場合 true を返します。
skipToEnd() ストリームを行末へ進めます。
column() → integer 行の何文字目かを返します。
match(pattern: string, ?consume: boolean, ?caseFold: boolean) → boolean 文字列が一致したら true を返し、consume に true を渡すか値を渡さない場合、一致した分ストリームを進めます。
match(pattern: regexp, ?consume: boolean) → array<string> 文字列が一致したら true を返し、consume に true を渡すか値を渡さない場合、一致した分ストリームを進めます。一致しない場合、null を返します。
  • match に渡る文字列は、行単位のようです
  • デフォルトでは、空行はスキップされるようです

簡単な例

以下のようなモードを作って読み込ませます。if, for, int をキーワード、数値部分を数字、// 以降をコメントにするモードです。

これを適用させると、以下のような感じになります。

他にもインデントの情報など色々と返せるようですが、コードに色付けするだけであれば、これで十分そうです。