web-dev-qa-db-ja.com

テキストエディターで構文を強調表示するための効率的なデータ構造は何ですか?

Ncursesライブラリを使用して、C++で非常に小さなテキストエディターを作成しています。これまでのところ、それは素晴らしい働きをします。 ギャップバッファー データ構造を実装して、行ベースのバッファーよりも編集を効率的にしました。 Ropesデータ構造を検討しましたが、これは非常に複雑に見えました。

しかし、私は今、構文強調表示を実装しようとしているので、これを行う適切な方法を考えることができません。ファイル全体を強調表示する必要がありますか、それとも現在のビューのみを強調表示する必要がありますか(ファイルの非表示部分は強調表示しません)。

スタイルデータ(太字、色など)を含むマイクロバッファーを保存して、希望を与えて使用する必要がありますか?

5
vinnylinux

テキストバッファーに構文強調表示情報を直接配置する必要はないと思います。代わりに、表示コードのデータ構造を追加します。

理由は次のとおりです。

選択などの機能を提供したら、おそらくアンカーの概念(バッファー内の特定の場所への安定したポインター、その場所の前に文字が挿入または削除された場合でも-実装のアイデアについては以下を参照)が必要になります。より長いテキストを扱う場合は、これらのアンカーを使用して、行の先頭のバッファーに高速なインデックスを提供する必要があります(ギャップバッファーを使用しているため、行番号をバッファー位置に変換する方法が必要です)。

私が得ているのは、高速の標準エディターコマンドを提供し、現在表示されているバッファーを表示するために、実際のテキストバッファーの他にいくつかのサポートデータ構造が必要なことです。ギャップバッファーを使用するという決定にもかかわらず、エディターは行ベースであり、どういうわけかそれをサポートする必要があります。では、テキストバッファー、その中へのアンカー(理想的には行の先頭)、および強調表示状態を取得し、(「テキストフラグメント」、「スタイル情報」のリストを出力する、行ベースの構文ハイライターを記述しないでください。 ")行の終わりまでペアリングします。表示コードはこの行を実際に表示するために使用しますか?その場で実行するほど高速でない場合は、行番号でインデックスが付けられたこれらのリストのキャッシュを作成できます。ファイル全体を一度にプロベイブすることもできますが、ファイル内を移動するたびにそれを行うと、パフォーマンスが低下するのではないかと思います。

長いコメントや文字列などの複数行のトークンのため、入力として蛍光ペンの状態が必要になります。通常、エディターは最初にファイルを開いたときに最初からファイルを表示するため、「すべてクリア」の状態で開始し、蛍光ペンコードを呼び出して最初の行の強調表示情報を吐き出し、蛍光ペンの状態を最後に維持できます。次の行の先頭の蛍光ペンの状態としての行(たとえば、「現在複数行コメント」または「すべてクリア」)。

したがって、基本的には、アンカーを実装し、インデックスを維持して、行番号をテキストバッファーアンカーにすばやく変換することをお勧めします。次に、このインデックスを拡張して、テキストバッファーにアンカーを提供するだけでなく、その行の構文ハイライト出力のキャッシュと、この行の先頭のハイライト状態も提供します。したがって、ユーザーが行を編集している場合は、バッファーの最上部で蛍光ペンを再起動する必要はありません。行の先頭で強調表示を再開するだけです。賢い場合は、バッファーの残り全体を強調表示する必要を回避することもできます(表示領域の下部または蛍光ペンと同じ状態の線に到達するとすぐに強調表示を停止すると思います実際には入っていますが、次の行のキャッシュされた状態と蛍光ペンの状態が一致しない場合は、次の蛍光ペンの状態に「古くなっている可能性がある」というフラグを付けます。

この方法でバッファの非常に小さなセクションのみを強調表示することで、通常は1行だけで済むと思います。ただし、「ファイルの終わりにジャンプ」などのエディタコマンドを除きます。この場合、構文を強調表示する必要があります。ハイライトがファイルの最後にあるべき状態を決定するためのバッファ全体。

編集:アンカーを実装する方法

アンカーを実装するには、イベントとリスナーを使用できます。バッファーがテキストを挿入または削除するコマンドを取得するたびに、これらのイベントが発生することをすべてのリスナーに通知します。次に、アンカーはこれらのイベントをリスナーとしてサブスクライブし、イベントの種類に基づいて自身を更新します。たとえば、3つの文字が挿入された場合beforeアンカー位置は、アンカー位置に3を追加する必要があります。文字が挿入された場合アンカーの位置、アクションは不要などです。したがって、基本的に、アンカーはバッファーオフセットを追跡し、ギャップバッファーからの変更イベントをサブスクライブするオブジェクトです。

8
Pascal