elm_code: Add basic scope parsing to syntax highlighting.

This is currently displayed by showing scope in the widget gutter
This commit is contained in:
Andy Williams 2017-11-14 19:12:56 +00:00
parent 1227f914e2
commit 95b0d7ca68
4 changed files with 133 additions and 12 deletions

View File

@ -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);
/**

View File

@ -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);

View File

@ -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,

View File

@ -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 <stdio.h>", 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);
}