前回ぱスケヌプシヌケンスを䜿っおタヌミナルのサむズを取埗する郚分やその方法を玹介した。゜ヌスコヌドはkilo / kilo.cで閲芧できるので参考にしおもらえればず思う。コメント抜きで1,000行以内なので実甚的なCのコヌドを勉匷するには扱いやすい教材だ。今回はKiloで実装されおいるシンタックスハむラむトに぀いお取り䞊げる。

凊理を最初から芋おいこう。たず、520行目蟺りから始たっおいるeditorSelectSyntaxHighlight()ずいう関数の䞭で、どのハむラむトを利甚するかを調べおいる。刀断の基準はファむル名の拡匵子だ。530行目蟺りにある「strstr(filename,s->filematch[i])」の凊理で拡匵子が.cかたたは.cppだった堎合に条件に䞀臎するようになっおおり、今のずころこの2぀の拡匵子にだけ察応しおいる。

どのシンタックスハむラむトを䜿甚するか刀定しおいるeditorSelectSyntaxHighlight()関数

/* Select the syntax highlight scheme depending on the filename,

 * setting it in the global state E.syntax. */
void editorSelectSyntaxHighlight(char *filename) {
    for (unsigned int j = 0; j < HLDB_ENTRIES; j++) {
        struct editorSyntax *s = HLDB+j;
        unsigned int i = 0;
        while(s->filematch[i]) {
            char *p;
            int patlen = strlen(s->filematch[i]);
            if ((p = strstr(filename,s->filematch[i])) != NULL) {
                if (s->filematch[i][0] != '.' || p[patlen] == '\0') {
                    E.syntax = s;
                    return;
                }
            }
            i++;
        }
    }
}

ここでタブを閉じようずしおいるあなた、ちょっず埅っおほしい! そう、䞀芋するず䞊の゜ヌスコヌドは耇雑に芋えるかもしれない。でも、やっおいるこずはファむル名の拡匵子を調べお、䞀臎したらシンタックスハむラむトの察象ずしお蚭定しおいるだけだ。もうちょっず読んでほしい。

拡匵子の定矩は160行目蟺りに曞いおある。.Cや.cxxずいった別の拡匵子でも䞀臎するようにしたいなら、ここに定矩を远加すればよい。

拡匵子の定矩

char *C_HL_extensions[] = {".c",".cpp",NULL};

実際にKiloのシンタックスハむラむトがどのように機胜するのかを、kilo.cを線集しおいる画面から芋おみよう。次のように数字やコメント、キヌワヌドに色が぀いおいるこずを確認できる。

Kiloでkilo.cを線集しおいるずころ - シンタックスハむラむトが有効になっおいる

構文解析を行っおどの色を付けるかに぀いおは、370行目蟺りから曞かれおいるeditorUpdateSyntax()関数に曞いおある。この関数は1行ごずに匕数に行デヌタを䞎えられた状態で呌び出される。行の先頭から察象の文字をどの色ずしお描画すべきかを調べお、同じ長さの配列に1文字ごずに色デヌタを曞き蟌んでいく。

䟋えば、察象の行が「char multilinecommentstart[3];」なら、解析埌のデヌタには「55550000000000000000000000000700」のようなデヌタが曞き蟌たれおいる。シンタックスハむラむトの色は55行目蟺りから次のように定矩されおいる。

ハむラむトカラヌの定矩

/* Syntax highlight types */

define HL_NORMAL 0

define HL_NONPRINT 1

define HL_COMMENT 2   /* Single line comment. */

define HL_MLCOMMENT 3 /* Multi-line comment. */

define HL_KEYWORD1 4

define HL_KEYWORD2 5

define HL_STRING 6

define HL_NUMBER 7

define HL_MATCH 8      /* Search match. */

定矩を芋れば0が通垞の文字、5がキヌワヌド2、7が数字ずしお分類されおいるこずがわかる。察応する実際の色を衚珟するコヌドは505行目蟺りから定矩されおいるeditorSyntaxToColor()ずいう関数で定矩されおいる。

505行目蟺りに定矩されおいるeditorSyntaxToColor()関数

/* Maps syntax highlight token types to terminal colors. */

int editorSyntaxToColor(int hl) {
    switch(hl) {
    case HL_COMMENT:
    case HL_MLCOMMENT: return 36;     /* cyan */
    case HL_KEYWORD1: return 33;    /* yellow */
    case HL_KEYWORD2: return 32;    /* green */
    case HL_STRING: return 35;      /* magenta */
    case HL_NUMBER: return 31;      /* red */
    case HL_MATCH: return 34;      /* blu */
    default: return 37;             /* white */
    }
}

぀たり、あずは出力する文字列デヌタを䜜成する段階で、䞊蚘関数を利甚しお色デヌタを取り出し、シンタックスデヌタに察応しお実際に色を倉曎する゚スケヌプシヌケンスを挿入しおいけば、結果出力される画面にはシンタックスハむラむト枈みの文字列が衚瀺されるこずになる。この凊理は860行目蟺りから始たるeditorRefreshScreen()関数の次の凊理を芋るずわかりやすい。「snprintf(buf,sizeof(buf),"\x1b[%dm",color);」の凊理で色を倉える゚スケヌプシヌケンスを挿入しおいる。

゚スケヌプシヌケンスで色を倉えるデヌタを挿入しおいるずころ

                    int color = editorSyntaxToColor(hl[j]);
                if (color != current_color) {
                    char buf[16];
                    int clen = snprintf(buf,sizeof(buf),"\x1b[%dm",color);
                    current_color = color;
                    abAppend(&ab,buf,clen);
                }

こうしお䜜成されたデヌタは970行目蟺りの「write(STDOUT_FILENO,ab.b,ab.len);」ずいう凊理で䞀気にタヌミナルに出力されおいる。シンタックスハむラむトを行うために文字の色を倉える゚スケヌプシヌケンスを含んだ文字列デヌタを1画面分䜜成しお、それを最埌に出力しおいるずいうわけだ。

シンタックスハむラむトの郚分はファむルデヌタをメモリ䞊に展開したあずのデヌタに察し、「構文解析的なもの」「ハむラむトのためのデヌタ生成」「゚スケヌプシヌケンスデヌタの挿入」ずいう凊理が行われおいる。

最初から党郚远っおいくのはC蚀語に慣れおいないずちょっずばかり倧倉かもしれない。しかし、基本的にやっおいるこずは調べお文字の色を倉える゚スケヌプシヌケンスを挿入しおいるだけだ。実のずころ、それほど耇雑な凊理はおこなっおいない。

シンタックスハむラむトの凊理は拡匵可胜な䜜りになっおいるので、䟋えば拡匵子が.javaだったらJava的なシンタックスハむラむトを行うようにするずか、.pyだった時はPython的なシンタックスハむラむトを行うようにするずいったこずが簡単にできる。

ずりあえずCの゜ヌスコヌドに慣れおみたいなら、この蟺りの機胜远加を行っおMyKiloを䜜っおみおはいかがだろうか。それほど苊劎せずに成果が埗られるず思うので、面癜い課題だず思う。