kilo

Kilo: minimal text editor written in C
git clone git://git.dimitrijedobrota.com/kilo.git
Log | Files | Refs

commit fb4217ce51a604a0d05a852d9c5bd804cc359bf0
parent ee4547f1f7c069b9aebf6899e50025a3f31f9cb3
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Sun,  9 Apr 2023 17:37:59 +0200

Extend syntax highlighting

* Add two more Keyword tags
* Add Operator tag
* Add Angle brackets tag
* Add support for individual character highlighting
* Extend C syntax highlighting
* Improve number literal detection

Diffstat:
Mkilo.c | 149++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 125 insertions(+), 24 deletions(-)

diff --git a/kilo.c b/kilo.c @@ -57,13 +57,29 @@ enum editorHighlight { HL_MLCOMMENT, HL_KEYWORD1, HL_KEYWORD2, - HL_STRING, + HL_KEYWORD3, + HL_KEYWORD4, + HL_MATCH, HL_NUMBER, - HL_MATCH + HL_OPERATORS, + HL_STRING, + HL_ABRAKETS, + + HL_BRACKETS, + HL_SBRACKETS, + HL_CBRACKETS, + HL_SEMICOLON, + HL_COMMA, }; -#define HL_HIGHLIGHT_NUMBERS (1 << 0) -#define HL_HIGHLIGHT_STRINGS (1 << 1) +#define HL_HIGHLIGHT_NUMBERS (1 << 0) +#define HL_HIGHLIGHT_STRINGS (1 << 1) +#define HL_HIGHLIGHT_ABRACKETS (1 << 2) +#define HL_HIGHLIGHT_BRACKETS (1 << 3) +#define HL_HIGHLIGHT_CBRACKETS (1 << 4) +#define HL_HIGHLIGHT_SBRACKETS (1 << 5) +#define HL_HIGHLIGHT_SEMICOLON (1 << 6) +#define HL_HIGHLIGHT_COMMA (1 << 7) /*** data ***/ @@ -71,6 +87,7 @@ struct editorSyntax { char *filetype; char **filematch; char **keywords; + char **operators; char *singleline_comment_start; char *multiline_comment_start; char *multiline_comment_end; @@ -109,15 +126,35 @@ struct editorConfig E; /*** filetypes ***/ char *C_HL_extensions[] = {".c", ".h", ".cpp", NULL}; -char *C_HL_keywords[] = {"switch", "if", "while", "for", "break", - "continue", "return", "else", "struct", "union", - "typedef", "static", "enum", "class", "case", - "int|", "long|", "double|", "float|", "char|", - "unsigned|", "signed|", "void|", NULL}; + +/* clang-format off */ +char *C_HL_keywords[] = { + "auto", "break", "case", "const", "continue", "default", + "do", "else", "enum", "extern", "for", "goto", + "if", "register", "return", "sizeof", "static", "struct", + "switch", "typedef", "union", "volatile", "while", + + "int|", "long|", "double|", "float|", + "char|", "unsigned|", "signed|", "void|", + + "#include#", "#error#", "#define#", "#undef#", + "#ifdef#", "#ifndef#", "#endif#", + + "__FILE__*", "__LINE__*", "__DATE__*", "__TIME__*", + "__STDC__*", "__STDC_VERSION__*", "__STDC_HOSTED__*", "NULL*", NULL}; +/* clang-format on */ + +char *C_HL_operators[] = { + "...", "<=>", "<<=", ">>=", "++", "--", "==", "!=", ">=", "<=", "&&", + "||", "<<", ">>", "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", + "->", "::", "**", "-", "*", "/", "%", ">", "<", "!", "~", + "&", "|", "^", "=", ".", "+", "?", ":", NULL}; struct editorSyntax HLDB[] = { - {"c", C_HL_extensions, C_HL_keywords, "//", "/*", "*/", - HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS}, + {"c", C_HL_extensions, C_HL_keywords, C_HL_operators, "//", "/*", "*/", + HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS | HL_HIGHLIGHT_ABRACKETS | + HL_HIGHLIGHT_BRACKETS | HL_HIGHLIGHT_CBRACKETS | + HL_HIGHLIGHT_SBRACKETS | HL_HIGHLIGHT_COMMA | HL_HIGHLIGHT_SEMICOLON}, }; #define HLDB_ENTRIES (sizeof(HLDB) / sizeof(HLDB[0])) @@ -243,7 +280,7 @@ int getWindowSize(int *rows, int *cols) { /*** syntax highlighting ***/ int is_separator(int c) { - return isspace(c) || c == '\0' || strchr(",.()+-/*=~%<>[];", c) != NULL; + return isspace(c) || c == '\0' || strchr(",.()+-/*=~%<>[]{};", c) != NULL; } void editorUpdateSyntax(erow *row) { @@ -253,6 +290,7 @@ void editorUpdateSyntax(erow *row) { if (E.syntax == NULL) return; char **keywords = E.syntax->keywords; + char **operators = E.syntax->operators; char *scs = E.syntax->singleline_comment_start; char *mcs = E.syntax->multiline_comment_start; @@ -262,7 +300,7 @@ void editorUpdateSyntax(erow *row) { int mcs_len = mcs ? strlen(mcs) : 0; int mce_len = mce ? strlen(mce) : 0; - int prev_sep = 1, in_string = 0; + int prev_sep = 1, in_string = 0, in_abrackets = 0; int in_comment = (row->idx > 0 && E.row[row->idx - 1].hl_open_comment); int i = 0; while (i < row->rsize) { @@ -319,9 +357,25 @@ void editorUpdateSyntax(erow *row) { } } + if (E.syntax->flags & HL_HIGHLIGHT_ABRACKETS) { + if (in_abrackets) { + row->hl[i++] = HL_ABRAKETS; + if (c == '>') in_abrackets = 0; + prev_sep = 1; + continue; + } else { + if (c == '<' && strrchr(row->chars, '>')) { + in_abrackets = 1; + row->hl[i++] = HL_ABRAKETS; + continue; + } + } + } + if (E.syntax->flags & HL_HIGHLIGHT_NUMBERS) { if ((isdigit(c) && (prev_sep || prev_hl == HL_NUMBER)) || - (c == '.' && prev_hl == HL_NUMBER)) { + ((c == '.' || c == 'x' || c == 'l' || c == 'u' || c == 'f') && + prev_hl == HL_NUMBER)) { row->hl[i] = HL_NUMBER; i++; prev_sep = 0; @@ -331,28 +385,65 @@ void editorUpdateSyntax(erow *row) { if (prev_sep) { int j; - for (j = 0; keywords[j]; j++) { int klen = strlen(keywords[j]); - int kw2 = keywords[j][klen - 1] == '|'; - if (kw2) klen--; + + enum editorHighlight hl = HL_KEYWORD1; + switch (keywords[j][--klen]) { + case '|': hl = HL_KEYWORD2; break; + case '#': hl = HL_KEYWORD3; break; + case '*': hl = HL_KEYWORD4; break; + default: klen++; + } if (!strncmp(&row->render[i], keywords[j], klen) && is_separator(row->render[i + klen])) { - memset(&row->hl[i], kw2 ? HL_KEYWORD2 : HL_KEYWORD1, klen); + memset(&row->hl[i], hl, klen); i += klen; - break; + prev_sep = 0; + goto next_iteration; } } + } - if (keywords[j] != NULL) { - prev_sep = 0; - continue; + { + int j; + for (j = 0; operators[j]; j++) { + int olen = strlen(operators[j]); + if (!strncmp(&row->render[i], operators[j], olen)) { + memset(&row->hl[i], HL_OPERATORS, olen); + i += olen; + prev_sep = 1; + goto next_iteration; + } } } + switch (c) { + case '(': + case ')': + if (E.syntax->flags & HL_HIGHLIGHT_BRACKETS) row->hl[i] = HL_BRACKETS; + break; + case '[': + case ']': + if (E.syntax->flags & HL_HIGHLIGHT_SBRACKETS) row->hl[i] = HL_SBRACKETS; + break; + case '{': + case '}': + if (E.syntax->flags & HL_HIGHLIGHT_CBRACKETS) row->hl[i] = HL_CBRACKETS; + break; + case ';': + if (E.syntax->flags & HL_HIGHLIGHT_SEMICOLON) row->hl[i] = HL_SEMICOLON; + break; + case ',': + if (E.syntax->flags & HL_HIGHLIGHT_COMMA) row->hl[i] = HL_COMMA; + break; + } + + // if ((prev_sep = is_separator(c))) row->hl[i] = HL_KEYWORD4; prev_sep = is_separator(c); i++; + next_iteration:; } int changed = (row->hl_open_comment != in_comment); @@ -367,9 +458,19 @@ int editorSyntaxToColor(int hl) { case HL_MLCOMMENT: return 36; case HL_STRING: return 35; case HL_KEYWORD1: return 33; - case HL_KEYWORD2: return 32; - case HL_NUMBER: return 31; + case HL_KEYWORD2: return 31; + case HL_KEYWORD3: return 91; + case HL_KEYWORD4: return 96; + case HL_OPERATORS: return 94; + case HL_NUMBER: return 32; case HL_MATCH: return 34; + case HL_ABRAKETS: return 93; + + case HL_BRACKETS: return 91; + case HL_SBRACKETS: return 37; + case HL_CBRACKETS: return 93; + case HL_SEMICOLON: return 93; + case HL_COMMA: return 91; default: return 37; } }