Skip to content

JA08_シンタックスハイライト

HAYAMA_Kaoru edited this page Oct 11, 2023 · 1 revision

Editor構造体の .Coloring フィールドに次の Coloring interface 要件を満たすオブジェクトを設定することで、入力中のテキストに色付けを行うことができます。

type Coloring interface {
	// Reset has to initialize receiver's fields and return default color.
	Init() ColorSequence
	// Next has to return color for the given rune.
	Next(rune) ColorSequence
}

readline.ColorSequenece は色情報を文字する型です。実態は int64 の整数型で 8bit ごとに区切って、エスケープシーケンスの ESC[..;...m で用いられる属性コードを格納します(下位バイトから順に属性コードを格納しますが、一番最下位バイトだけは要素の個数を格納します。文字列ではなく、数値にしたのは前後の文字での属性の変更を素早く行うためでした。が、複雑にした結果、遅くなっている可能性も…)

ReadLine は文字に属性コードを設定する時、まず最初に Init()メソッドをコールして、デフォルト色を得ます。その後、最初の文字から順に一文字ずつ取り出して Next メソッドをコールし、各文字に対応する[属性コード]を得ようとします。なお、属性コードの実際の出力は ReadLine 側で最適化されており、n個目の属性コードが (n-1)個目の属性コードから変化があった時だけ ESC[...m として出力するようになっています。

ColorSequence は次のようなコンストラクタ・メソッドを持っています。

  • readline.SGR1(X)ESC[Xm 相当の ColorSequence を作成します
  • readline.SGR2(X,Y)ESC[X;Ym 相当の ColorSequence を作成します
  • readline.SGR3(X,Y,Z)ESC[X;Y;Zm 相当の ColorSequence を作成します
  • readline.SGR4(W,X,Y,Z)ESC[W;X;Y;Zm 相当の ColorSequence を作成します
  • (c ColorSequence) Add(value int) ColorSequence
    作成済の ColorSequence にもう一要素追加したものを返します
  • (c ColorSequence) Chain(value ColorSequence) ColorSequence
    インスタンス自身と引数の ColorSequence を連結したものを返します。

go-readline-ny にはいくつか定義済みの定数も用意されています

const (
	Black ColorSequence = 3 | ((30 + iota) << colorCodeBitSize) | (49 << (colorCodeBitSize * 2)) | (1 << (colorCodeBitSize * 3))
	Red
	Green
	Yellow
	Blue
	Magenta
	Cyan
	White
	_
	DefaultForeGroundColor
)

const (
	DarkGray ColorSequence = 3 | ((30 + iota) << colorCodeBitSize) | (22 << (colorCodeBitSize * 2)) | (49 << (colorCodeBitSize * 3))
	DarkRed
	DarkGree
	DarkYellow
	DarkBlue
	DarkMagenta
	DarkCyan
	DarkWhite
	_
	DarkDefaultForeGroundColor
)

あと、シンプルな実装例として coloring.VimBatch という構造体も用意しています。vim でバッチファイルを開いた時のシンタックスハイライトに似たような色付けを意図したものです。具体的には

  • 二重引用符で囲まれた内側は、マゼンダ
  • パーセントで囲まれた内側は、思案
  • 全角空白は背景赤色
  • & は黄土色
  • その他は端末のデフォルト色

といった簡単な色付けを行っています。