From 95b0d7ca68c0b5c95cacb9e7cea7c80cf7520823 Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Tue, 14 Nov 2017 19:12:56 +0000 Subject: [PATCH] elm_code: Add basic scope parsing to syntax highlighting. This is currently displayed by showing scope in the widget gutter --- src/lib/elementary/elm_code_line.h | 3 + src/lib/elementary/elm_code_syntax.c | 43 +++++++++++++ src/lib/elementary/elm_code_widget.c | 68 +++++++++++++++++---- src/tests/elementary/elm_code_test_syntax.c | 31 ++++++++++ 4 files changed, 133 insertions(+), 12 deletions(-) diff --git a/src/lib/elementary/elm_code_line.h b/src/lib/elementary/elm_code_line.h index 88196893de..8e832ff5ed 100644 --- a/src/lib/elementary/elm_code_line.h +++ b/src/lib/elementary/elm_code_line.h @@ -30,6 +30,7 @@ typedef struct _Elm_Code_Line Elm_Code_Status_Type status; Eina_List *tokens; + unsigned int scope; void *data; char *status_text; @@ -104,6 +105,8 @@ EAPI void elm_code_line_token_add(Elm_Code_Line *line, int start, int end, int l EAPI void elm_code_line_tokens_clear(Elm_Code_Line *line); +EAPI unsigned int elm_code_line_scope_get(Elm_Code_Line *line); + EAPI Eina_Bool elm_code_line_contains_widget_cursor(Elm_Code_Line *line); /** diff --git a/src/lib/elementary/elm_code_syntax.c b/src/lib/elementary/elm_code_syntax.c index 2cef6c33a2..39046a194a 100644 --- a/src/lib/elementary/elm_code_syntax.c +++ b/src/lib/elementary/elm_code_syntax.c @@ -15,9 +15,30 @@ typedef struct _Elm_Code_Syntax const char *comment_single; const char *comment_start; const char *comment_end; + int (*scope_change)(Elm_Code_Line *line); const char *keywords[]; } Elm_Code_Syntax; +static int +_elm_code_syntax_scope_change_braces(Elm_Code_Line *line) +{ + unsigned int length, i; + const char *content; + int change = 0; + + content = elm_code_line_text_get(line, &length); + + for (i = 0; i < length; i++) + { + if (*(content + i) == '{') + change++; + else if (*(content + i) == '}') + change--; + } + + return change; +} + static Elm_Code_Syntax _elm_code_syntax_c = { "{}()[]:;%^/*+&|~!=<->,.", @@ -26,6 +47,7 @@ static Elm_Code_Syntax _elm_code_syntax_c = "//", "/*", "*/", + _elm_code_syntax_scope_change_braces, {"auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", \ "float", "for", "goto", "if", "int", "long", "register", "return", "short", "signed", "sizeof", "static", \ "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", NULL} @@ -39,6 +61,7 @@ static Elm_Code_Syntax _elm_code_syntax_rust = "//", NULL, NULL, + _elm_code_syntax_scope_change_braces, {"as", "break", "const", "continue", "create", "else", "enum", "extern", "false", "fn", "for", "if", \ "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return", "Self", "self", \ "static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where", "while", @@ -53,6 +76,7 @@ static Elm_Code_Syntax _elm_code_syntax_py = "#", "\"\"\"", "\"\"\"", + NULL, {"False", "None", "True", "and", "as", "assert", "break", "class", \ "continue", "def", "del", "elif", "else", "except", "finally", "for", \ "from", "global", "if", "import", "in", "is", "lambda", "nonlocal", "not", \ @@ -67,6 +91,7 @@ static Elm_Code_Syntax _elm_code_syntax_eo = "//", "[[", "]]", + _elm_code_syntax_scope_change_braces, {"byte", "ubyte", "char", "short", "ushort", "int", "uint", "long", "ulong", \ "llong", "ullong", "int8", "uint8", "int16", "uint16", "int32", "uint32", \ "int64", "uint64", "int128", "uint128", "size", "ssize", "intptr", "uintptr", \ @@ -88,6 +113,7 @@ static Elm_Code_Syntax _elm_code_syntax_go = "//", "/*", "*/", + _elm_code_syntax_scope_change_braces, { "break", "case", "chan", "const", "default", "defer", "else", "fallthrough", "for", "func", "go", "goto", \ "if", "import", "interface", "map", "package", "range", "return", "select", "struct", "switch", "type", "var", \ "true", "false", "iota", "nil", \ @@ -104,6 +130,7 @@ static Elm_Code_Syntax _elm_code_syntax_md = NULL, "", + NULL, {} }; @@ -223,6 +250,21 @@ _previous_line_continue_type(Elm_Code_Line *line) return ELM_CODE_TOKEN_TYPE_DEFAULT; } +unsigned int +_previous_line_scope(Elm_Code_Line *line) +{ + Elm_Code_Line *prev; + + if (line->number < 2) + return 0; + + prev = elm_code_file_line_get(line->file, line->number - 1); + if (!prev) + return 0; + + return prev->scope; +} + EAPI void elm_code_syntax_parse_line(Elm_Code_Syntax *syntax, Elm_Code_Line *line) { @@ -232,6 +274,7 @@ elm_code_syntax_parse_line(Elm_Code_Syntax *syntax, Elm_Code_Line *line) Elm_Code_Token_Type previous_type; EINA_SAFETY_ON_NULL_RETURN(syntax); + line->scope = _previous_line_scope(line) + _elm_code_syntax_scope_change_braces(line); i = 0; content = elm_code_line_text_get(line, &length); diff --git a/src/lib/elementary/elm_code_widget.c b/src/lib/elementary/elm_code_widget.c index fc20eac6ec..8fa06023de 100644 --- a/src/lib/elementary/elm_code_widget.c +++ b/src/lib/elementary/elm_code_widget.c @@ -16,6 +16,7 @@ typedef enum { ELM_CODE_WIDGET_COLOR_GUTTER_BG = ELM_CODE_TOKEN_TYPE_COUNT, + ELM_CODE_WIDGET_COLOR_GUTTER_SCOPE_BG, ELM_CODE_WIDGET_COLOR_GUTTER_FG, ELM_CODE_WIDGET_COLOR_WHITESPACE, ELM_CODE_WIDGET_COLOR_SELECTION, @@ -189,13 +190,45 @@ _elm_code_widget_fill_line_tokens(Elm_Code_Widget *widget, Evas_Textgrid_Cell *c } } +static Eina_Bool +_elm_code_widget_line_in_scope(Elm_Code_Line *line, Elm_Code_Line *fromline) +{ + Elm_Code_Line *midline; + unsigned int number; + + if (line->scope == 0 || fromline->scope == 0) + return EINA_FALSE; + + if (line->number == fromline->number) + return EINA_TRUE; + + if (line->scope < fromline->scope) + return EINA_FALSE; + + number = fromline->number; + while (number != line->number) + { + midline = elm_code_file_line_get(line->file, number); + + if (midline->scope < fromline->scope) + return EINA_FALSE; + + if (line->number < fromline->number) + number--; + else + number++; + } + return EINA_TRUE; +} + static void -_elm_code_widget_fill_gutter(Elm_Code_Widget *widget, Evas_Textgrid_Cell *cells, - int width, Elm_Code_Status_Type status, int line) +_elm_code_widget_fill_line_gutter(Elm_Code_Widget *widget, Evas_Textgrid_Cell *cells, + int width, Elm_Code_Line *line) { char *number = NULL; int gutter, g; Elm_Code_Widget_Data *pd; + Elm_Code_Line *cursor_line; pd = efl_data_scope_get(widget, ELM_CODE_WIDGET_CLASS); gutter = elm_code_widget_text_left_gutter_width_get(widget); @@ -203,17 +236,28 @@ _elm_code_widget_fill_gutter(Elm_Code_Widget *widget, Evas_Textgrid_Cell *cells, if (width < gutter) return; - cells[gutter-1].codepoint = status_icons[status]; + cells[gutter-1].codepoint = status_icons[line->status]; cells[gutter-1].bold = 1; cells[gutter-1].fg = ELM_CODE_WIDGET_COLOR_GUTTER_FG; - cells[gutter-1].bg = (status == ELM_CODE_STATUS_TYPE_DEFAULT) ? ELM_CODE_WIDGET_COLOR_GUTTER_BG : status; + if (line->status == ELM_CODE_STATUS_TYPE_DEFAULT) + { + cursor_line = elm_code_file_line_get(line->file, pd->cursor_line); + if (_elm_code_widget_line_in_scope(line, cursor_line)) + cells[gutter-1].bg = ELM_CODE_WIDGET_COLOR_GUTTER_SCOPE_BG; + else + cells[gutter-1].bg = ELM_CODE_WIDGET_COLOR_GUTTER_BG; + } + else + { + cells[gutter-1].bg = line->status; + } if (pd->show_line_numbers) { - if (line > 0) + if (line->number > 0) { number = malloc(sizeof(char) * gutter); - snprintf(number, gutter, "%*d", gutter - 1, line); + snprintf(number, gutter, "%*d", gutter - 1, line->number); } for (g = 0; g < gutter - 1; g++) { @@ -375,7 +419,7 @@ _elm_code_widget_fill_line(Elm_Code_Widget *widget, Elm_Code_Line *line) cells[x].bg = _elm_code_widget_status_type_get(widget, line, x - gutter + 1); } - _elm_code_widget_fill_gutter(widget, cells, w, line->status, line->number); + _elm_code_widget_fill_line_gutter(widget, cells, w, line); _elm_code_widget_fill_line_tokens(widget, cells, w, line); _elm_code_widget_fill_selection(widget, line, cells, gutter, w); @@ -634,11 +678,9 @@ _elm_code_widget_cursor_move(Elm_Code_Widget *widget, Elm_Code_Widget_Data *pd, _elm_code_widget_cursor_ensure_visible(widget); if (oldrow != pd->cursor_line) - { - if (oldrow <= elm_code_file_lines_get(code->file)) - _elm_code_widget_fill_line(widget, elm_code_file_line_get(pd->code->file, oldrow)); - } - _elm_code_widget_fill_line(widget, elm_code_file_line_get(pd->code->file, pd->cursor_line)); + _elm_code_widget_refresh(widget, line_obj); + else + _elm_code_widget_fill_line(widget, elm_code_file_line_get(pd->code->file, pd->cursor_line)); elm_layout_signal_emit(pd->cursor_rect, "elm,action,show,cursor", "elm"); } @@ -1813,6 +1855,8 @@ _elm_code_widget_setup_palette(Evas_Object *o) 51, 153, 255, 255); evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_WIDGET_COLOR_GUTTER_BG, 75, 75, 75, 255); + evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_WIDGET_COLOR_GUTTER_SCOPE_BG, + 54, 54, 54, 255); evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_WIDGET_COLOR_GUTTER_FG, 139, 139, 139, 255); evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_WIDGET_COLOR_WHITESPACE, diff --git a/src/tests/elementary/elm_code_test_syntax.c b/src/tests/elementary/elm_code_test_syntax.c index f3f5c3acd9..7e1d0d13f6 100644 --- a/src/tests/elementary/elm_code_test_syntax.c +++ b/src/tests/elementary/elm_code_test_syntax.c @@ -116,8 +116,39 @@ START_TEST (elm_code_syntax_c) } END_TEST +START_TEST (elm_code_syntax_scope_change_braces_test) +{ + Elm_Code_File *file; + Elm_Code_Line *line; + Elm_Code *code; + + elm_init(1, NULL); + code = elm_code_create(); + code->file->mime = "text/x-csrc"; + elm_code_parser_standard_add(code, ELM_CODE_PARSER_STANDARD_SYNTAX); + file = code->file; + + elm_code_file_line_append(file, "#include ", 18, NULL); + line = elm_code_file_line_get(file, 1); + ck_assert_int_eq(0, line->scope); + + elm_code_file_line_append(file, "int main() {", 12, NULL); + line = elm_code_file_line_get(file, 2); + ck_assert_int_eq(1, line->scope); + + elm_code_file_line_append(file, "}", 1, NULL); + elm_code_file_line_append(file, "", 0, NULL); + line = elm_code_file_line_get(file, 4); + ck_assert_int_eq(0, line->scope); + + elm_code_free(code); + elm_shutdown(); +} +END_TEST + void elm_code_test_syntax(TCase *tc) { tcase_add_test(tc, elm_code_syntax_lookup); tcase_add_test(tc, elm_code_syntax_c); + tcase_add_test(tc, elm_code_syntax_scope_change_braces_test); }