良い時間
構文の強調表示を備えたエディターまたはコードエディターの開発における私の経験についてお話ししたいと思います。 これは、カスタム言語用のエディターです。 この投稿の本質は、開発プロセスの詳細な説明ではありません-最も興味深い点のみに焦点を当てます。
Scintillaは、コードエディターを作成するための最も有名な無料コンポーネントの1つであり、 wxStyledTextCtrlは
wxWidgets
ラッパーです。
Scintillaは、使用されるほとんどのプログラミング言語をサポートしているため、新しいレクサーの追加は、最も近い言語との類推によって行われることがよくあります。 このプロセスについては、 ここで詳しく説明します 。 この方法の実装は非常に簡単ですが、重大な欠点が1つあります。プロジェクトにすべてのシンチラコードを含める必要があります。 小規模で比較的安定したプロジェクトの場合、これはそれほど重要ではありませんが、大きくて活発な開発プロジェクトの場合、多くの問題を引き起こします。 Scintillaコンポーネント自体ではなく、ラッパー(たとえば
wxStyledTextCtrl
を使用する場合、サポートはさらに困難に
wxStyledTextCtrl
ます。 別の方法は、コンテナ内のレクサーのいわゆる実装です 。
シンチラのレクサー統合
最初に、簡単な方法についていくつか説明します。 一般に、独自のレクサーを作成するには、コードの変更された部分の色付けを担当する関数を1つだけ記述する必要があります。
static void ColouriseDoc (unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler)
。 指定した範囲を色付けまたは定型化するとは、各文字のスタイルを指定することを意味します。 同時に、コンポーネントは
[startPos, startPos + length - 1]
あり、テキストレンダリング自体を最適化し、範囲
[startPos, startPos + length - 1]
が整数行数であることを保証します。これにより、パーサーの実装が容易になります。
コンテナにレクサーを実装する
クラスの作成から始めました- 例に示すように、
wxStyledTextCtrl
子孫です。 前の方法と同様に、レクサーに必要な関数は1
EVT_STC_STYLENEEDED
です。この場合、
EVT_STC_STYLENEEDED
イベントで
EVT_STC_STYLENEEDED
ます。
編集したファイルのサイズが50〜60行を超えない場合、イベントによって送信された範囲を安全に無視し、ファイルの内容全体を様式化できるため、レクサーが大幅に簡素化されることが経験からわかっています。 行数が多い場合は、スタイルを
GetEndStyled()
からではなく、前の行から更新することをお
GetEndStyled()
ます。 前の方法と同様に、整数行のイベントが発生します。
マニュアルで言及し忘れたもの
この段階で既に遭遇した困難の1つは、イベントが頻繁にトリガーされることです。 デバッガーでのコンポーネントの動作に関する小規模な調査では、範囲[n、m]をスタイル設定した後、最後の様式化されたシンボルはまったくmではないことが示されました。 ほとんどの場合、それは前のシンボルであり、シンボルは2〜3文字で区切られている場合があります。 いくつかの理由がありました。
- すべてのカスタムスタイルには0より大きいインデックスが必要です。
- スペースや改行など、絶対にすべてのスタイルを設定する必要があります
- スタイルは順番に適用する必要があります。 最初にスタイルを範囲[0、100]に適用し、次に[0、10]に適用する場合-最後の様式化されたものは100番目ではなく10番目です
行ごとのパーサーを実装し、不必要なイベント呼び出しを避けるために、最後の定型化された文字のインデックスを保存する必要がありました。
SetStyleBytesによるSetStyling
ほとんどすべての例で、スタイルの使用は一連のコマンドとして示されています。
StartStyling(...);
SetStyling(...);
この場合、文字は文字ごとに適用されますが、これはまったく効果がなく、これを使用する方がよいです。これにより、コンポーネントにスタイルインデックスの事前に準備されたベクトルを渡すことができます
StartStyling(...);
SetStyleBytes(...);
正直なところ、SetStyling関数を使用する必要がある場合は見つかりませんでした。
ロシアの手紙
スタイルがロシア語の文字を含む単語を正しく受け入れるためには、
pos = PositionAfter(pos)
順番に実行して、最後の文字のインデックスを正しく計算する必要があります。 自動置換
pos = PositionBefore(pos)
呼び出すときに、単語の一部を取得するには、位置を計算する同様の方法を適用する必要があります。
コードの一部を隠す(折りたたみ)
この関数の実装は特定の問題を引き起こさず、ドキュメントにギャップはありませんでした。 折り畳みは
SetFoldLevel(...)
行レベルに基づいているだけで、たとえば、レクサーに直接配置しました(そのため、行
SetFoldLevel(...)
パーサーの方が便利です)。
オートコンプリート機能
この機能はドキュメントでは比較的詳細に説明されていますが、欠落しているものがいくつかあります。 まず、
AutoCompShow(...)
コンポーネントの標準機能
AutoCompShow(...)
は、入力された単語の部分ではなく、配置のみでフィルタリングされることが判明しました。 次に、ユーザーが選択した単語を置き換える
AutoCompSelect()
関数は、明らかな理由もなく例外を引き起こすことが多いため、役に立たないことが判明しました。 代わりに、フラグAutoCompSetChooseSingle()を設定することをお勧めします。
通話のヒント
wxStyledTextCtrl
1つの劣らず便利な機能は、CallTipShow()呼び出しヒントを表示することです。 これを使用することは、
AutoCompShow()
ルックアップ関数を使用することに似ています。 同時に通過することに注意してください。
上記の機能が
wxStyledTextCtrl
、
wxStyledTextCtrl
使用
wxStyledTextCtrl
と、かなり複雑なレクサーをコンテナに実装でき
wxStyledTextCtrl
。