From e4fef248987840ae95351119ce48b9855148a2cc Mon Sep 17 00:00:00 2001 From: Andy Williams Date: Sun, 22 Jan 2017 21:58:20 +0000 Subject: [PATCH] elm_code: Syntax highlighting for multiline comments --- src/lib/elementary/elm_code_syntax.c | 116 ++++++++++++++++++++++++++-- src/tests/elementary/elm_code_test_syntax.c | 24 +++--- 2 files changed, 125 insertions(+), 15 deletions(-) diff --git a/src/lib/elementary/elm_code_syntax.c b/src/lib/elementary/elm_code_syntax.c index 96becb9..a0f4a9e 100644 --- a/src/lib/elementary/elm_code_syntax.c +++ b/src/lib/elementary/elm_code_syntax.c @@ -10,12 +10,18 @@ typedef struct _Elm_Code_Syntax { const char *symbols; + const char *comment_single; + const char *comment_start; + const char *comment_end; const char *keywords[]; } Elm_Code_Syntax; static Elm_Code_Syntax _elm_code_syntax_c = { - "{}()[]:;*&|!=<->,.", + "{}()[]:;/*+&|!=<->,.", + "//", + "/*", + "*/", {"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} @@ -52,19 +58,97 @@ _elm_code_syntax_parse_token(Elm_Code_Syntax *syntax, Elm_Code_Line *line, unsig } } +static Eina_Bool +_content_starts_with(const char *content, const char *prefix, unsigned int length) +{ + unsigned int i; + unsigned int prefix_length; + + prefix_length = strlen(prefix); + if (!content || length < prefix_length) + return EINA_FALSE; + + for (i = 0; i < prefix_length; i++) + if (content[i] != prefix[i]) + return EINA_FALSE; + + return EINA_TRUE; +} + +static Eina_Bool +_starts_single_comment(Elm_Code_Syntax *syntax, const char *content, unsigned int length) +{ + return _content_starts_with(content, syntax->comment_single, length); +} + +static Eina_Bool +_starts_comment(Elm_Code_Syntax *syntax, const char *content, unsigned int length) +{ + return _content_starts_with(content, syntax->comment_start, length); +} + +static Eina_Bool +_ends_comment(Elm_Code_Syntax *syntax, const char *content, unsigned int length) +{ + return _content_starts_with(content, syntax->comment_end, length); +} + +static Elm_Code_Token_Type +_previous_line_continue_type(Elm_Code_Line *line) +{ + Elm_Code_Line *prev; + Elm_Code_Token *token; + Eina_List *item; + + if (line->number < 2) + return ELM_CODE_TOKEN_TYPE_DEFAULT; + + prev = elm_code_file_line_get(line->file, line->number - 1); + if (!prev || !prev->tokens) + return ELM_CODE_TOKEN_TYPE_DEFAULT; + + EINA_LIST_FOREACH(prev->tokens, item, token) + if (token->continues) + return token->type; + + return ELM_CODE_TOKEN_TYPE_DEFAULT; +} + EAPI void elm_code_syntax_parse_line(Elm_Code_Syntax *syntax, Elm_Code_Line *line) { - unsigned int i, count, length; + unsigned int i, i2, count, length; const char *content; const char *sym, *ptr; + Elm_Code_Token_Type previous_type; EINA_SAFETY_ON_NULL_RETURN(syntax); - content = elm_code_line_text_get(line, &length); + i = 0; + content = elm_code_line_text_get(line, &length); + previous_type = _previous_line_continue_type(line); + if (previous_type == ELM_CODE_TOKEN_TYPE_COMMENT) + { + for (i2 = i; i2 < length; i2++) + if (_ends_comment(syntax, content + i2, length - i2)) + { + i2 += strlen(syntax->comment_end) - 1; + break; + } + + elm_code_line_token_add(line, 1, i2, 1, ELM_CODE_TOKEN_TYPE_COMMENT); + if (i2 == length) + { + Elm_Code_Token *token = eina_list_last_data_get(line->tokens); + token->continues = EINA_TRUE; + return; + } + i = i2 + 1; + } + ptr = content; count = 0; - for (i = 0; i < length; i++) + for (; i < length; i++) { if (_elm_code_text_char_is_whitespace(content[i])) { @@ -81,11 +165,31 @@ elm_code_syntax_parse_line(Elm_Code_Syntax *syntax, Elm_Code_Line *line) elm_code_line_token_add(line, i, length - 1, 1, ELM_CODE_TOKEN_TYPE_PREPROCESSOR); return; } - else if (count == 1 && content[i-1] == '/' && content[i] == '/') + else if (_starts_single_comment(syntax, content + i, length - i)) { - elm_code_line_token_add(line, i - 1, length - 1, 1, ELM_CODE_TOKEN_TYPE_COMMENT); + elm_code_line_token_add(line, i, length, 1, ELM_CODE_TOKEN_TYPE_COMMENT); return; } + else if (_starts_comment(syntax, content + i, length - i)) + { + for (i2 = i+strlen(syntax->comment_start); i2 < length; i2++) + if (_ends_comment(syntax, content + i2, length - i2)) + { + i2 += strlen(syntax->comment_end) - 1; + break; + } + + elm_code_line_token_add(line, i, i2, 1, ELM_CODE_TOKEN_TYPE_COMMENT); + if (i2 == length) + { + Elm_Code_Token *token = eina_list_last_data_get(line->tokens); + token->continues = EINA_TRUE; + return; + } + i = i2; + count = 0; + continue; + } else if (content[i] == '"') { unsigned int start = i, end; diff --git a/src/tests/elementary/elm_code_test_syntax.c b/src/tests/elementary/elm_code_test_syntax.c index 0eeea6d..8d08878 100644 --- a/src/tests/elementary/elm_code_test_syntax.c +++ b/src/tests/elementary/elm_code_test_syntax.c @@ -67,6 +67,9 @@ START_TEST (elm_code_syntax_c) elm_code_widget_syntax_enabled_set(widget, EINA_TRUE); _append_line(file, "#include "); + _append_line(file, "/**"); + _append_line(file, " * The main method."); + _append_line(file, " */"); _append_line(file, "int main(int argc, char **argv)"); _append_line(file, "{"); _append_line(file, " // display a welcome greeting"); @@ -78,22 +81,25 @@ START_TEST (elm_code_syntax_c) _append_line(file, "}"); _assert_line_token_types(file, 1, 1, (Elm_Code_Token_Type[1]){ELM_CODE_TOKEN_TYPE_PREPROCESSOR}); - _assert_line_token_types(file, 2, 8, (Elm_Code_Token_Type[8]){ELM_CODE_TOKEN_TYPE_KEYWORD, ELM_CODE_TOKEN_TYPE_BRACE, + _assert_line_token_types(file, 2, 1, (Elm_Code_Token_Type[1]){ELM_CODE_TOKEN_TYPE_COMMENT}); + _assert_line_token_types(file, 3, 1, (Elm_Code_Token_Type[1]){ELM_CODE_TOKEN_TYPE_COMMENT}); + _assert_line_token_types(file, 4, 1, (Elm_Code_Token_Type[1]){ELM_CODE_TOKEN_TYPE_COMMENT}); + _assert_line_token_types(file, 5, 8, (Elm_Code_Token_Type[8]){ELM_CODE_TOKEN_TYPE_KEYWORD, ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_KEYWORD, ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_KEYWORD, ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_BRACE}); - _assert_line_token_types(file, 3, 1, (Elm_Code_Token_Type[1]){ELM_CODE_TOKEN_TYPE_BRACE}); - _assert_line_token_types(file, 4, 1, (Elm_Code_Token_Type[1]){ELM_CODE_TOKEN_TYPE_COMMENT}); - _assert_line_token_types(file, 5, 5, (Elm_Code_Token_Type[5]){ELM_CODE_TOKEN_TYPE_KEYWORD, ELM_CODE_TOKEN_TYPE_BRACE, + _assert_line_token_types(file, 6, 1, (Elm_Code_Token_Type[1]){ELM_CODE_TOKEN_TYPE_BRACE}); + _assert_line_token_types(file, 7, 1, (Elm_Code_Token_Type[1]){ELM_CODE_TOKEN_TYPE_COMMENT}); + _assert_line_token_types(file, 8, 5, (Elm_Code_Token_Type[5]){ELM_CODE_TOKEN_TYPE_KEYWORD, ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_NUMBER, ELM_CODE_TOKEN_TYPE_BRACE}); - _assert_line_token_types(file, 6, 8, (Elm_Code_Token_Type[8]){ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_STRING, + _assert_line_token_types(file, 9, 8, (Elm_Code_Token_Type[8]){ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_STRING, ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_NUMBER, ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_BRACE}); - _assert_line_token_types(file, 7, 1, (Elm_Code_Token_Type[1]){ELM_CODE_TOKEN_TYPE_KEYWORD}); - _assert_line_token_types(file, 8, 4, (Elm_Code_Token_Type[4]){ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_STRING, + _assert_line_token_types(file, 10, 1, (Elm_Code_Token_Type[1]){ELM_CODE_TOKEN_TYPE_KEYWORD}); + _assert_line_token_types(file, 11, 4, (Elm_Code_Token_Type[4]){ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_STRING, ELM_CODE_TOKEN_TYPE_BRACE, ELM_CODE_TOKEN_TYPE_BRACE}); - _assert_line_token_types(file, 9, 3, (Elm_Code_Token_Type[3]){ELM_CODE_TOKEN_TYPE_KEYWORD, + _assert_line_token_types(file, 12, 3, (Elm_Code_Token_Type[3]){ELM_CODE_TOKEN_TYPE_KEYWORD, ELM_CODE_TOKEN_TYPE_NUMBER, ELM_CODE_TOKEN_TYPE_BRACE}); - _assert_line_token_types(file, 10, 1, (Elm_Code_Token_Type[1]){ELM_CODE_TOKEN_TYPE_BRACE}); + _assert_line_token_types(file, 13, 1, (Elm_Code_Token_Type[1]){ELM_CODE_TOKEN_TYPE_BRACE}); elm_code_free(code); elm_shutdown(); -- 2.7.4