Scintilla/Some notes on using Scintilla

Last-modified: 2008-02-24 (日) 07:57:53

Scintillaを使う上でのノート

自動インデントの実装

主要な考えは、新しい行の後にインデントを加えるためにSCN_CHARADDED通知を使うことである。


通知のlParamは、追加された文字を特定するchメンバーを指定するSCNotification構造へのポインタである。
新しい行が加えられた場合、前行を検索できる。そして、同じインデントを新しい行に追加する。


ここにSciTEからのコードの関連部分がある: (SciTE.cxx SciTEWindow::CharAdded)

if (ch == '\r' || ch == '\n') {
    char linebuf[1000];
    int curLine = GetCurrentLineNumber();
    int lineLength = SendEditor(SCI_LINELENGTH, curLine);
    //Platform::DebugPrintf("[CR] %d len = %d\n", curLine, lineLength);
    if (curLine > 0 && lineLength <= 2) {
    int prevLineLength = SendEditor(SCI_LINELENGTH, curLine - 1);
    if (prevLineLength < sizeof(linebuf)) {
        WORD  buflen = sizeof(linebuf);
        memcpy(linebuf, &buflen, sizeof(buflen));
        SendEditor(EM_GETLINE, curLine - 1,
                   reinterpret_cast<LPARAM>(static_cast<char *>(linebuf)));
        linebuf[prevLineLength] = '\0';
        for (int pos = 0; linebuf[pos]; pos++) {
            if (linebuf[pos] != ' ' && linebuf[pos] != '\t')
                linebuf[pos] = '\0';
        }
        SendEditor(EM_REPLACESEL, 0, reinterpret_cast<LPARAM>(static_cast<char *>(linebuf)));
    }
}

もちろん、よりしゃれた取り扱いを実装することもできる。
たとえば、前行が制御構造の始まりであれば、1個のタブで字下げすることができるだろう。
(あなたが字下げスタイルを仮定する場合)

構文スタイルの実装

構文スタイルはSCN_STYLENEEDED通知で扱われる。
Scintillaはスタイルされたテキストの最後の動向を保持する。- これはSCI_GETENDSTYLEDで取得する。
SCN_STYLENEEDED通知に対応して、ENDSTYLEDから通知で指定された位置までスタイルをテキストに適用するべきである。


ここにSciTEからのコードの関連部分がある: (SciTE.cxx)

void SciTEWindow::Notify(SCNotification *notification) {
    switch (notification->nmhdr.code) {
    case SCN_STYLENEEDED: {
            if (notification->nmhdr.idFrom == IDM_SRCWIN) {
                int endStyled = SendEditor(SCI_GETENDSTYLED);
                int lineEndStyled = SendEditor(EM_LINEFROMCHAR, endStyled);
                endStyled = SendEditor(EM_LINEINDEX, lineEndStyled);
                Colourise(endStyled, notification->position);

Colourize(start, end)はテキストの指定された範囲を取得し、keywords.cxxのColourizeDocが呼ばれる。
それは次を呼ぶことによって開始される:

SendMessage(hwnd, SCI_STARTSTYLING, startPos, 31);

そしてテキストのそれぞれのトークンのために、次を呼ぶ:

SendMessage(hwnd, SCI_SETSTYLING, length, style);

スタイルは、SCI_STYLESET...メッセージで使うところで定義された0から31までの数字である。

コールチップの実装

はじめの挿入句が加えられるとき、SCN_CHARADDED通知は捕まえるために使われる。
次に現在行から前の単語を取得する:

char linebuf[1000];
int current = SendEditor(SCI_GETCURLINE, sizeof(linebuf),
     reinterpret_cast<LPARAM>(static_cast<char *>(linebuf)));
int pos = SendEditor(SCI_GETCURRENTPOS);
int startword = current - 1;
while (startword > 0 && isalpha(linebuf[startword - 1]))
     startword--;
linebuf[current - 1] = '\0';
char* word = linebuf + startword;

そして、コールチップが利用可能であるなら表示する。
コールチップはすぐ下の位置に現れる。
コールチップは改行(\n)によって複数行を分ける。

pos = SendMessage(hwnd, SCI_GETCURRENTPOS, 0, 0);
SendMessageText(hwnd, SCI_CALLTIPSHOW, pos - wordLen - 1, calltip);

閉じ括弧が入力されたらコールチップを削除することができる:

if (SendMessage(hwnd, SCI_CALLTIPACTIVE, 0, 0))
     SendMessage(hwnd, SCI_CALLTIPCANCEL, 0, 0);

明らかに、適切なコールチップテキストを供給する世話をするアプリケーション上にある。


引数の間のカンマの数を数えてコールチップの対応する部分を強調するよう、SciTEは進んでいる。
このコードはContinueCallTipである。