forked from enlightenment/efl
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:
parent
1227f914e2
commit
95b0d7ca68
|
@ -30,6 +30,7 @@ typedef struct _Elm_Code_Line
|
||||||
|
|
||||||
Elm_Code_Status_Type status;
|
Elm_Code_Status_Type status;
|
||||||
Eina_List *tokens;
|
Eina_List *tokens;
|
||||||
|
unsigned int scope;
|
||||||
|
|
||||||
void *data;
|
void *data;
|
||||||
char *status_text;
|
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 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);
|
EAPI Eina_Bool elm_code_line_contains_widget_cursor(Elm_Code_Line *line);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,9 +15,30 @@ typedef struct _Elm_Code_Syntax
|
||||||
const char *comment_single;
|
const char *comment_single;
|
||||||
const char *comment_start;
|
const char *comment_start;
|
||||||
const char *comment_end;
|
const char *comment_end;
|
||||||
|
int (*scope_change)(Elm_Code_Line *line);
|
||||||
const char *keywords[];
|
const char *keywords[];
|
||||||
} Elm_Code_Syntax;
|
} 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 =
|
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", \
|
{"auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", \
|
||||||
"float", "for", "goto", "if", "int", "long", "register", "return", "short", "signed", "sizeof", "static", \
|
"float", "for", "goto", "if", "int", "long", "register", "return", "short", "signed", "sizeof", "static", \
|
||||||
"struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", NULL}
|
"struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", NULL}
|
||||||
|
@ -39,6 +61,7 @@ static Elm_Code_Syntax _elm_code_syntax_rust =
|
||||||
"//",
|
"//",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
_elm_code_syntax_scope_change_braces,
|
||||||
{"as", "break", "const", "continue", "create", "else", "enum", "extern", "false", "fn", "for", "if", \
|
{"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", \
|
"impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return", "Self", "self", \
|
||||||
"static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where", "while",
|
"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", \
|
{"False", "None", "True", "and", "as", "assert", "break", "class", \
|
||||||
"continue", "def", "del", "elif", "else", "except", "finally", "for", \
|
"continue", "def", "del", "elif", "else", "except", "finally", "for", \
|
||||||
"from", "global", "if", "import", "in", "is", "lambda", "nonlocal", "not", \
|
"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", \
|
{"byte", "ubyte", "char", "short", "ushort", "int", "uint", "long", "ulong", \
|
||||||
"llong", "ullong", "int8", "uint8", "int16", "uint16", "int32", "uint32", \
|
"llong", "ullong", "int8", "uint8", "int16", "uint16", "int32", "uint32", \
|
||||||
"int64", "uint64", "int128", "uint128", "size", "ssize", "intptr", "uintptr", \
|
"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", \
|
{ "break", "case", "chan", "const", "default", "defer", "else", "fallthrough", "for", "func", "go", "goto", \
|
||||||
"if", "import", "interface", "map", "package", "range", "return", "select", "struct", "switch", "type", "var", \
|
"if", "import", "interface", "map", "package", "range", "return", "select", "struct", "switch", "type", "var", \
|
||||||
"true", "false", "iota", "nil", \
|
"true", "false", "iota", "nil", \
|
||||||
|
@ -104,6 +130,7 @@ static Elm_Code_Syntax _elm_code_syntax_md =
|
||||||
NULL,
|
NULL,
|
||||||
"<!--",
|
"<!--",
|
||||||
"-->",
|
"-->",
|
||||||
|
NULL,
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -223,6 +250,21 @@ _previous_line_continue_type(Elm_Code_Line *line)
|
||||||
return ELM_CODE_TOKEN_TYPE_DEFAULT;
|
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
|
EAPI void
|
||||||
elm_code_syntax_parse_line(Elm_Code_Syntax *syntax, Elm_Code_Line *line)
|
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;
|
Elm_Code_Token_Type previous_type;
|
||||||
|
|
||||||
EINA_SAFETY_ON_NULL_RETURN(syntax);
|
EINA_SAFETY_ON_NULL_RETURN(syntax);
|
||||||
|
line->scope = _previous_line_scope(line) + _elm_code_syntax_scope_change_braces(line);
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
content = elm_code_line_text_get(line, &length);
|
content = elm_code_line_text_get(line, &length);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ELM_CODE_WIDGET_COLOR_GUTTER_BG = ELM_CODE_TOKEN_TYPE_COUNT,
|
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_GUTTER_FG,
|
||||||
ELM_CODE_WIDGET_COLOR_WHITESPACE,
|
ELM_CODE_WIDGET_COLOR_WHITESPACE,
|
||||||
ELM_CODE_WIDGET_COLOR_SELECTION,
|
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
|
static void
|
||||||
_elm_code_widget_fill_gutter(Elm_Code_Widget *widget, Evas_Textgrid_Cell *cells,
|
_elm_code_widget_fill_line_gutter(Elm_Code_Widget *widget, Evas_Textgrid_Cell *cells,
|
||||||
int width, Elm_Code_Status_Type status, int line)
|
int width, Elm_Code_Line *line)
|
||||||
{
|
{
|
||||||
char *number = NULL;
|
char *number = NULL;
|
||||||
int gutter, g;
|
int gutter, g;
|
||||||
Elm_Code_Widget_Data *pd;
|
Elm_Code_Widget_Data *pd;
|
||||||
|
Elm_Code_Line *cursor_line;
|
||||||
|
|
||||||
pd = efl_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
|
pd = efl_data_scope_get(widget, ELM_CODE_WIDGET_CLASS);
|
||||||
gutter = elm_code_widget_text_left_gutter_width_get(widget);
|
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)
|
if (width < gutter)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cells[gutter-1].codepoint = status_icons[status];
|
cells[gutter-1].codepoint = status_icons[line->status];
|
||||||
cells[gutter-1].bold = 1;
|
cells[gutter-1].bold = 1;
|
||||||
cells[gutter-1].fg = ELM_CODE_WIDGET_COLOR_GUTTER_FG;
|
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 (pd->show_line_numbers)
|
||||||
{
|
{
|
||||||
if (line > 0)
|
if (line->number > 0)
|
||||||
{
|
{
|
||||||
number = malloc(sizeof(char) * gutter);
|
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++)
|
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);
|
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_line_tokens(widget, cells, w, line);
|
||||||
|
|
||||||
_elm_code_widget_fill_selection(widget, line, cells, gutter, w);
|
_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);
|
_elm_code_widget_cursor_ensure_visible(widget);
|
||||||
|
|
||||||
if (oldrow != pd->cursor_line)
|
if (oldrow != pd->cursor_line)
|
||||||
{
|
_elm_code_widget_refresh(widget, line_obj);
|
||||||
if (oldrow <= elm_code_file_lines_get(code->file))
|
else
|
||||||
_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_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");
|
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);
|
51, 153, 255, 255);
|
||||||
evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_WIDGET_COLOR_GUTTER_BG,
|
evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_WIDGET_COLOR_GUTTER_BG,
|
||||||
75, 75, 75, 255);
|
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,
|
evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_WIDGET_COLOR_GUTTER_FG,
|
||||||
139, 139, 139, 255);
|
139, 139, 139, 255);
|
||||||
evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_WIDGET_COLOR_WHITESPACE,
|
evas_object_textgrid_palette_set(o, EVAS_TEXTGRID_PALETTE_STANDARD, ELM_CODE_WIDGET_COLOR_WHITESPACE,
|
||||||
|
|
|
@ -116,8 +116,39 @@ START_TEST (elm_code_syntax_c)
|
||||||
}
|
}
|
||||||
END_TEST
|
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)
|
void elm_code_test_syntax(TCase *tc)
|
||||||
{
|
{
|
||||||
tcase_add_test(tc, elm_code_syntax_lookup);
|
tcase_add_test(tc, elm_code_syntax_lookup);
|
||||||
tcase_add_test(tc, elm_code_syntax_c);
|
tcase_add_test(tc, elm_code_syntax_c);
|
||||||
|
tcase_add_test(tc, elm_code_syntax_scope_change_braces_test);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue