wxStyledTextCtrlに基づく構文強調表示を備えたクロスプラットフォームエディターの開発

良い時間


構文の強調表示を備えたエディターまたはコードエディターの開発における私の経験についてお話ししたいと思います。 これは、カスタム言語用のエディターです。 この投稿の本質は、開発プロセスの詳細な説明ではありません-最も興味深い点のみに焦点を当てます。

Scintillaは、コードエディターを作成するための最も有名な無料コンポーネントの1つであり、 wxStyledTextCtrlwxWidgetsラッパーです。
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文字で区切られている場合があります。 いくつかの理由がありました。

行ごとのパーサーを実装し、不必要なイベント呼び出しを避けるために、最後の定型化された文字のインデックスを保存する必要がありました。

SetStyleBytesによるSetStyling

ほとんどすべての例で、スタイルの使用は一連のコマンドとして示されています。
StartStyling(...);
SetStyling(...);

この場合、文字は文字ごとに適用されますが、これはまったく効果がなく、これを使用する方がよいです。これにより、コンポーネントにスタイルインデックスの事前に準備されたベクトルを渡すことができます
StartStyling(...);
SetStyleBytes(...);

正直なところ、SetStyling関数を使用する必要がある場合は見つかりませんでした。

ロシアの手紙

スタイルがロシア語の文字を含む単語を正しく受け入れるためには、 pos = PositionAfter(pos)順番に実行して、最後の文字のインデックスを正しく計算する必要があります。 自動置換pos = PositionBefore(pos)呼び出すときに、単語の一部を取得するには、位置を計算する同様の方法を適用する必要があります。

コードの一部を隠す(折りたたみ)

この関数の実装は特定の問題を引き起こさず、ドキュメントにギャップはありませんでした。 折り畳みはSetFoldLevel(...)行レベルに基づいているだけで、たとえば、レクサーに直接配置しました(そのため、行SetFoldLevel(...)パーサーの方が便利です)。

オートコンプリート機能

この機能はドキュメントでは比較的詳細に説明されていますが、欠落しているものがいくつかあります。 まず、 AutoCompShow(...)コンポーネントの標準機能AutoCompShow(...)は、入力された単語の部分ではなく、配置のみでフィルタリングされることが判明しました。 次に、ユーザーが選択した単語を置き換えるAutoCompSelect()関数は、明らかな理由もなく例外を引き起こすことが多いため、役に立たないことが判明しました。 代わりに、フラグAutoCompSetChooseSingle()を設定することをお勧めします。

通話のヒント

wxStyledTextCtrl 1つの劣らず便利な機能は、CallTipShow()呼び出しヒントを表示することです。 これを使用することは、 AutoCompShow()ルックアップ関数を使用することに似ています。 同時に通過することに注意してください。

上記の機能がwxStyledTextCtrlwxStyledTextCtrl使用wxStyledTextCtrlと、かなり複雑なレクサーをコンテナに実装できwxStyledTextCtrl

Source: https://habr.com/ru/post/J129019/


All Articles