forked from enlightenment/efl
elm_code: Add initial simple syntax highlighting for C code
For c source and headers lookup a simple syntax definition. Use a very simple text processing line by line to tokenise. Simple but it gets us one step closer to cross-language syntax
This commit is contained in:
parent
3090e9c3ae
commit
5851a9d4a8
|
@ -278,7 +278,8 @@ includesunstable_HEADERS = \
|
||||||
lib/elementary/elm_code_text.h \
|
lib/elementary/elm_code_text.h \
|
||||||
lib/elementary/elm_code_indent.h \
|
lib/elementary/elm_code_indent.h \
|
||||||
lib/elementary/elm_code_file.h \
|
lib/elementary/elm_code_file.h \
|
||||||
lib/elementary/elm_code_parse.h
|
lib/elementary/elm_code_parse.h \
|
||||||
|
lib/elementary/elm_code_syntax.h
|
||||||
includesunstabledir = $(includedir)/elementary-@VMAJ@
|
includesunstabledir = $(includedir)/elementary-@VMAJ@
|
||||||
|
|
||||||
nodist_includesunstable_HEADERS = \
|
nodist_includesunstable_HEADERS = \
|
||||||
|
@ -557,6 +558,7 @@ lib_elementary_libelementary_la_SOURCES = \
|
||||||
lib/elementary/elm_code_indent.c \
|
lib/elementary/elm_code_indent.c \
|
||||||
lib/elementary/elm_code_file.c \
|
lib/elementary/elm_code_file.c \
|
||||||
lib/elementary/elm_code_parse.c \
|
lib/elementary/elm_code_parse.c \
|
||||||
|
lib/elementary/elm_code_syntax.c \
|
||||||
lib/elementary/elm_code_widget_selection.c \
|
lib/elementary/elm_code_widget_selection.c \
|
||||||
lib/elementary/elm_code_widget.c \
|
lib/elementary/elm_code_widget.c \
|
||||||
lib/elementary/elm_code_diff_widget.c \
|
lib/elementary/elm_code_diff_widget.c \
|
||||||
|
@ -1321,6 +1323,7 @@ tests_elementary_elm_suite_SOURCES = \
|
||||||
tests/elementary/elm_code_test_basic.c \
|
tests/elementary/elm_code_test_basic.c \
|
||||||
tests/elementary/elm_code_test_line.c \
|
tests/elementary/elm_code_test_line.c \
|
||||||
tests/elementary/elm_code_test_parse.c \
|
tests/elementary/elm_code_test_parse.c \
|
||||||
|
tests/elementary/elm_code_test_syntax.c \
|
||||||
tests/elementary/elm_code_test_text.c \
|
tests/elementary/elm_code_test_text.c \
|
||||||
tests/elementary/elm_code_test_indent.c \
|
tests/elementary/elm_code_test_indent.c \
|
||||||
tests/elementary/elm_code_test_widget.c \
|
tests/elementary/elm_code_test_widget.c \
|
||||||
|
|
|
@ -294,6 +294,7 @@ void test_colorclass(void *data, Evas_Object *obj, void *event_info);
|
||||||
|
|
||||||
void test_code_welcome(void *data, Evas_Object *obj, void *event_info);
|
void test_code_welcome(void *data, Evas_Object *obj, void *event_info);
|
||||||
void test_code_editor(void *data, Evas_Object *obj, void *event_info);
|
void test_code_editor(void *data, Evas_Object *obj, void *event_info);
|
||||||
|
void test_code_syntax(void *data, Evas_Object *obj, void *event_info);
|
||||||
void test_code_mirror(void *data, Evas_Object *obj, void *event_info);
|
void test_code_mirror(void *data, Evas_Object *obj, void *event_info);
|
||||||
void test_code_log(void *data, Evas_Object *obj, void *event_info);
|
void test_code_log(void *data, Evas_Object *obj, void *event_info);
|
||||||
void test_code_diff(void *data, Evas_Object *obj, void *event_info);
|
void test_code_diff(void *data, Evas_Object *obj, void *event_info);
|
||||||
|
@ -732,6 +733,7 @@ add_tests:
|
||||||
//------------------------------//
|
//------------------------------//
|
||||||
ADD_TEST(NULL, "Advanced Entries", "Code Entry Markup", test_code_welcome);
|
ADD_TEST(NULL, "Advanced Entries", "Code Entry Markup", test_code_welcome);
|
||||||
ADD_TEST(NULL, "Advanced Entries", "Code Editor", test_code_editor);
|
ADD_TEST(NULL, "Advanced Entries", "Code Editor", test_code_editor);
|
||||||
|
ADD_TEST(NULL, "Advanced Entries", "Code Syntax", test_code_syntax);
|
||||||
ADD_TEST(NULL, "Advanced Entries", "Mirrored Editor", test_code_mirror);
|
ADD_TEST(NULL, "Advanced Entries", "Mirrored Editor", test_code_mirror);
|
||||||
ADD_TEST(NULL, "Advanced Entries", "Logger", test_code_log);
|
ADD_TEST(NULL, "Advanced Entries", "Logger", test_code_log);
|
||||||
ADD_TEST(NULL, "Advanced Entries", "Diff Comparison", test_code_diff);
|
ADD_TEST(NULL, "Advanced Entries", "Diff Comparison", test_code_diff);
|
||||||
|
|
|
@ -108,6 +108,39 @@ _elm_code_test_editor_setup(Evas_Object *parent, Eina_Bool log)
|
||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Evas_Object *
|
||||||
|
_elm_code_test_syntax_setup(Evas_Object *parent)
|
||||||
|
{
|
||||||
|
Elm_Code *code;
|
||||||
|
Elm_Code_Widget *widget;
|
||||||
|
|
||||||
|
code = elm_code_create();
|
||||||
|
widget = efl_add(ELM_CODE_WIDGET_CLASS, parent, elm_obj_code_widget_code_set(efl_added, code));
|
||||||
|
elm_obj_code_widget_font_set(widget, NULL, 14);
|
||||||
|
elm_obj_code_widget_editable_set(widget, EINA_TRUE);
|
||||||
|
elm_obj_code_widget_syntax_enabled_set(widget, EINA_TRUE);
|
||||||
|
elm_obj_code_widget_code_get(widget)->file->mime = "text/x-csrc";
|
||||||
|
elm_obj_code_widget_show_whitespace_set(widget, EINA_TRUE);
|
||||||
|
elm_obj_code_widget_line_numbers_set(widget, EINA_TRUE);
|
||||||
|
|
||||||
|
_append_line(code->file, "#include <stdio.h>");
|
||||||
|
_append_line(code->file, "int main(int argc, char **argv)");
|
||||||
|
_append_line(code->file, "{");
|
||||||
|
_append_line(code->file, " // display a welcome greeting");
|
||||||
|
_append_line(code->file, " if (argc > 0)");
|
||||||
|
_append_line(code->file, " printf(\"Hello, %s!\\n\", argv[0]);");
|
||||||
|
_append_line(code->file, " else");
|
||||||
|
_append_line(code->file, " printf(\"Hello, World!\\n\");");
|
||||||
|
_append_line(code->file, " return 0;");
|
||||||
|
_append_line(code->file, "}");
|
||||||
|
|
||||||
|
evas_object_size_hint_weight_set(widget, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||||
|
evas_object_size_hint_align_set(widget, EVAS_HINT_FILL, EVAS_HINT_FILL);
|
||||||
|
evas_object_show(widget);
|
||||||
|
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
|
||||||
static Evas_Object *
|
static Evas_Object *
|
||||||
_elm_code_test_mirror_setup(Elm_Code *code, char *font_name, Evas_Object *parent)
|
_elm_code_test_mirror_setup(Elm_Code *code, char *font_name, Evas_Object *parent)
|
||||||
{
|
{
|
||||||
|
@ -201,6 +234,21 @@ test_code_editor(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *eve
|
||||||
evas_object_show(win);
|
evas_object_show(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_code_syntax(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
|
||||||
|
{
|
||||||
|
Evas_Object *win, *screen;
|
||||||
|
|
||||||
|
win = _test_code_win_create("code-syntax", "Code Syntax");
|
||||||
|
screen = elm_box_add(win);
|
||||||
|
evas_object_size_hint_weight_set(screen, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
|
||||||
|
elm_box_pack_end(screen, _elm_code_test_syntax_setup(screen));
|
||||||
|
elm_win_resize_object_add(win, screen);
|
||||||
|
evas_object_show(screen);
|
||||||
|
|
||||||
|
evas_object_show(win);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
test_code_log(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
|
test_code_log(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "elm_code_indent.h"
|
#include "elm_code_indent.h"
|
||||||
#include "elm_code_file.h"
|
#include "elm_code_file.h"
|
||||||
#include "elm_code_parse.h"
|
#include "elm_code_parse.h"
|
||||||
|
#include "elm_code_syntax.h"
|
||||||
#include "elm_code_widget.eo.h"
|
#include "elm_code_widget.eo.h"
|
||||||
#include "elm_code_widget_legacy.h"
|
#include "elm_code_widget_legacy.h"
|
||||||
#include "elm_code_widget_selection.h"
|
#include "elm_code_widget_selection.h"
|
||||||
|
|
|
@ -128,6 +128,7 @@ EAPI Elm_Code_File *elm_code_file_open(Elm_Code *code, const char *path)
|
||||||
ret = elm_code_file_new(code);
|
ret = elm_code_file_new(code);
|
||||||
file = eina_file_open(path, EINA_FALSE);
|
file = eina_file_open(path, EINA_FALSE);
|
||||||
ret->file = file;
|
ret->file = file;
|
||||||
|
ret->mime = efreet_mime_type_get(path);
|
||||||
lastindex = 1;
|
lastindex = 1;
|
||||||
|
|
||||||
ret->map = eina_file_map_all(file, EINA_FILE_POPULATE);
|
ret->map = eina_file_map_all(file, EINA_FILE_POPULATE);
|
||||||
|
|
|
@ -22,6 +22,7 @@ struct _Elm_Code_File
|
||||||
Eina_List *lines;
|
Eina_List *lines;
|
||||||
Eina_File *file;
|
Eina_File *file;
|
||||||
void *map;
|
void *map;
|
||||||
|
const char *mime;
|
||||||
|
|
||||||
Elm_Code_File_Line_Ending line_ending;
|
Elm_Code_File_Line_Ending line_ending;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "elm_code_private.h"
|
#include "elm_code_private.h"
|
||||||
|
|
||||||
|
EAPI Elm_Code_Parser *ELM_CODE_PARSER_STANDARD_SYNTAX = NULL;
|
||||||
EAPI Elm_Code_Parser *ELM_CODE_PARSER_STANDARD_DIFF = NULL;
|
EAPI Elm_Code_Parser *ELM_CODE_PARSER_STANDARD_DIFF = NULL;
|
||||||
EAPI Elm_Code_Parser *ELM_CODE_PARSER_STANDARD_TODO = NULL;
|
EAPI Elm_Code_Parser *ELM_CODE_PARSER_STANDARD_TODO = NULL;
|
||||||
|
|
||||||
|
@ -126,6 +127,34 @@ _elm_code_parser_diff_trim_leading(Elm_Code_Line *line, unsigned int count)
|
||||||
line->length -= count;
|
line->length -= count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define _PARSE_C_SYMBOLS "{}()[]:;*&|!=<->,."
|
||||||
|
#define _PARSE_C_KEYWORDS {"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}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_elm_code_parser_syntax_parse_line(Elm_Code_Line *line, void *data EINA_UNUSED)
|
||||||
|
{
|
||||||
|
Elm_Code_Syntax *syntax;
|
||||||
|
|
||||||
|
syntax = elm_code_syntax_for_mime_get(line->file->mime);
|
||||||
|
if (syntax)
|
||||||
|
elm_code_syntax_parse_line(syntax, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_elm_code_parser_syntax_parse_file(Elm_Code_File *file, void *data EINA_UNUSED)
|
||||||
|
{
|
||||||
|
Elm_Code_Syntax *syntax;
|
||||||
|
INF("Parse syntax of file with mime \"%s\"", file->mime);
|
||||||
|
|
||||||
|
syntax = elm_code_syntax_for_mime_get(file->mime);
|
||||||
|
if (!syntax)
|
||||||
|
WRN("Unsupported mime in parser");
|
||||||
|
else
|
||||||
|
elm_code_syntax_parse_file(syntax, file);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_elm_code_parser_diff_parse_line(Elm_Code_Line *line, void *data EINA_UNUSED)
|
_elm_code_parser_diff_parse_line(Elm_Code_Line *line, void *data EINA_UNUSED)
|
||||||
{
|
{
|
||||||
|
@ -200,6 +229,8 @@ _elm_code_parser_free(Elm_Code_Parser *parser)
|
||||||
void
|
void
|
||||||
_elm_code_parse_setup()
|
_elm_code_parse_setup()
|
||||||
{
|
{
|
||||||
|
ELM_CODE_PARSER_STANDARD_SYNTAX = _elm_code_parser_new(_elm_code_parser_syntax_parse_line,
|
||||||
|
_elm_code_parser_syntax_parse_file);
|
||||||
ELM_CODE_PARSER_STANDARD_DIFF = _elm_code_parser_new(_elm_code_parser_diff_parse_line,
|
ELM_CODE_PARSER_STANDARD_DIFF = _elm_code_parser_new(_elm_code_parser_diff_parse_line,
|
||||||
_elm_code_parser_diff_parse_file);
|
_elm_code_parser_diff_parse_file);
|
||||||
ELM_CODE_PARSER_STANDARD_TODO = _elm_code_parser_new(_elm_code_parser_todo_parse_line, NULL);
|
ELM_CODE_PARSER_STANDARD_TODO = _elm_code_parser_new(_elm_code_parser_todo_parse_line, NULL);
|
||||||
|
|
|
@ -12,6 +12,7 @@ extern "C" {
|
||||||
|
|
||||||
typedef struct _Elm_Code_Parser Elm_Code_Parser;
|
typedef struct _Elm_Code_Parser Elm_Code_Parser;
|
||||||
|
|
||||||
|
extern EAPI Elm_Code_Parser *ELM_CODE_PARSER_STANDARD_SYNTAX; /**< A provided parser to provide syntax highlighting */
|
||||||
extern EAPI Elm_Code_Parser *ELM_CODE_PARSER_STANDARD_DIFF; /**< A provided parser that will mark up diff text */
|
extern EAPI Elm_Code_Parser *ELM_CODE_PARSER_STANDARD_DIFF; /**< A provided parser that will mark up diff text */
|
||||||
extern EAPI Elm_Code_Parser *ELM_CODE_PARSER_STANDARD_TODO; /**< A provided parser that will highlight TODO and FIXME lines */
|
extern EAPI Elm_Code_Parser *ELM_CODE_PARSER_STANDARD_TODO; /**< A provided parser that will highlight TODO and FIXME lines */
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef ELM_CODE_PRIVATE_H
|
#ifndef ELM_CODE_PRIVATE_H
|
||||||
# define ELM_CODE_PRIVATE_H
|
# define ELM_CODE_PRIVATE_H
|
||||||
|
|
||||||
|
#include "elm_priv.h"
|
||||||
|
|
||||||
Eina_Bool _elm_code_text_char_is_whitespace(char c);
|
Eina_Bool _elm_code_text_char_is_whitespace(char c);
|
||||||
|
|
||||||
/* Private parser callbacks */
|
/* Private parser callbacks */
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "elementary_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <Eina.h>
|
||||||
|
#include "Elementary.h"
|
||||||
|
|
||||||
|
#include "elm_code_private.h"
|
||||||
|
|
||||||
|
typedef struct _Elm_Code_Syntax
|
||||||
|
{
|
||||||
|
const char *symbols;
|
||||||
|
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}
|
||||||
|
};
|
||||||
|
|
||||||
|
EAPI Elm_Code_Syntax *
|
||||||
|
elm_code_syntax_for_mime_get(const char *mime)
|
||||||
|
{
|
||||||
|
if (!strcmp("text/x-chdr", mime) || !strcmp("text/x-csrc", mime))
|
||||||
|
return &_elm_code_syntax_c;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_elm_code_syntax_parse_token(Elm_Code_Syntax *syntax, Elm_Code_Line *line, unsigned int pos, const char *token, unsigned int length)
|
||||||
|
{
|
||||||
|
const char **keyword;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (keyword = syntax->keywords; *keyword; keyword++)
|
||||||
|
if (strlen(*keyword) == length && !strncmp(token, *keyword, length))
|
||||||
|
{
|
||||||
|
elm_code_line_token_add(line, pos, pos + length - 1, 1, ELM_CODE_TOKEN_TYPE_KEYWORD);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
if (!isdigit(token[i]))
|
||||||
|
break;
|
||||||
|
if (i == length - 1)
|
||||||
|
elm_code_line_token_add(line, pos, pos + length - 1, 1, ELM_CODE_TOKEN_TYPE_NUMBER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
elm_code_syntax_parse_line(Elm_Code_Syntax *syntax, Elm_Code_Line *line)
|
||||||
|
{
|
||||||
|
unsigned int i, count, length;
|
||||||
|
const char *content;
|
||||||
|
const char *sym, *ptr;
|
||||||
|
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN(syntax);
|
||||||
|
|
||||||
|
content = elm_code_line_text_get(line, &length);
|
||||||
|
ptr = content;
|
||||||
|
count = 0;
|
||||||
|
for (i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
if (_elm_code_text_char_is_whitespace(content[i]))
|
||||||
|
{
|
||||||
|
if (count)
|
||||||
|
_elm_code_syntax_parse_token(syntax, line, ptr-content, ptr, count);
|
||||||
|
|
||||||
|
ptr += count+1;
|
||||||
|
count = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content[i] == '#')
|
||||||
|
{
|
||||||
|
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] == '/')
|
||||||
|
{
|
||||||
|
elm_code_line_token_add(line, i - 1, length - 1, 1, ELM_CODE_TOKEN_TYPE_COMMENT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (content[i] == '"')
|
||||||
|
{
|
||||||
|
unsigned int start = i, end;
|
||||||
|
|
||||||
|
for (i++; content[i] != '"' && i < length; i++) {}
|
||||||
|
end = i;
|
||||||
|
|
||||||
|
elm_code_line_token_add(line, start, end, 1, ELM_CODE_TOKEN_TYPE_STRING);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (content[i] == '\'')
|
||||||
|
{
|
||||||
|
unsigned int start = i, end;
|
||||||
|
|
||||||
|
for (i++; content[i] != '\'' && i < length; i++) {}
|
||||||
|
end = i;
|
||||||
|
|
||||||
|
elm_code_line_token_add(line, start, end, 1, ELM_CODE_TOKEN_TYPE_STRING);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (sym = syntax->symbols; *sym; sym++)
|
||||||
|
if (content[i] == *sym)
|
||||||
|
{
|
||||||
|
if (count)
|
||||||
|
_elm_code_syntax_parse_token(syntax, line, ptr-content, ptr, count);
|
||||||
|
|
||||||
|
elm_code_line_token_add(line, i, i, 1, ELM_CODE_TOKEN_TYPE_BRACE);
|
||||||
|
|
||||||
|
ptr = content + i+1;
|
||||||
|
count = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count)
|
||||||
|
_elm_code_syntax_parse_token(syntax, line, ptr-content, ptr, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
elm_code_syntax_parse_file(Elm_Code_Syntax *syntax, Elm_Code_File *file EINA_UNUSED)
|
||||||
|
{
|
||||||
|
EINA_SAFETY_ON_NULL_RETURN(syntax);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
#ifndef ELM_CODE_SYNTAX_H_
|
||||||
|
# define ELM_CODE_SYNTAX_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief These routines are used for handling the parsing of Elm Code content.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _Elm_Code_Syntax Elm_Code_Syntax;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Syntax highlighting helper functions.
|
||||||
|
* @defgroup Syntax Parsing and marking up syntax in files
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* Syntax functions for adding syntax highlighting to elm code.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup a syntax definition from a mime type.
|
||||||
|
* If there is no syntax known NULL will be returned.
|
||||||
|
*
|
||||||
|
* @param mime The mime type to be looked up for a matching syntax definition
|
||||||
|
* @return A syntax definition, if one is found, or NULL
|
||||||
|
*
|
||||||
|
* @ingroup Syntax
|
||||||
|
*/
|
||||||
|
EAPI Elm_Code_Syntax *elm_code_syntax_for_mime_get(const char *mime);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a line and apply the syntax definition by inserting Elm_Code_Token into the line.
|
||||||
|
*
|
||||||
|
* @param syntax The syntax definition to use (from elm_code_syntax_for_mime_get)
|
||||||
|
* @param line The line that contains the content to parse and will receive the tokens
|
||||||
|
*
|
||||||
|
* @ingroup Syntax
|
||||||
|
*/
|
||||||
|
EAPI void elm_code_syntax_parse_line(Elm_Code_Syntax *syntax, Elm_Code_Line *line);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a file and apply the syntax definition one line at a time.
|
||||||
|
*
|
||||||
|
* @param syntax The syntax definition to use (from elm_code_syntax_for_mime_get)
|
||||||
|
* @param file The file to parse - each line in the file will be processed
|
||||||
|
*
|
||||||
|
* @ingroup Syntax
|
||||||
|
*/
|
||||||
|
EAPI void elm_code_syntax_parse_file(Elm_Code_Syntax *syntax, Elm_Code_File *file);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ELM_CODE_SYNTAX_H_ */
|
|
@ -172,7 +172,11 @@ elm_code_line_text_insert(Elm_Code_Line *line, unsigned int position, const char
|
||||||
line->length += length;
|
line->length += length;
|
||||||
|
|
||||||
file = line->file;
|
file = line->file;
|
||||||
elm_code_callback_fire(file->parent, &ELM_CODE_EVENT_LINE_LOAD_DONE, line);
|
if (file->parent)
|
||||||
|
{
|
||||||
|
_elm_code_parse_line(file->parent, line);
|
||||||
|
elm_code_callback_fire(file->parent, &ELM_CODE_EVENT_LINE_LOAD_DONE, line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EAPI void
|
EAPI void
|
||||||
|
@ -207,7 +211,11 @@ elm_code_line_text_remove(Elm_Code_Line *line, unsigned int position, int length
|
||||||
line->length -= length;
|
line->length -= length;
|
||||||
|
|
||||||
file = line->file;
|
file = line->file;
|
||||||
elm_code_callback_fire(file->parent, &ELM_CODE_EVENT_LINE_LOAD_DONE, line);
|
if (file->parent)
|
||||||
|
{
|
||||||
|
_elm_code_parse_line(file->parent, line);
|
||||||
|
elm_code_callback_fire(file->parent, &ELM_CODE_EVENT_LINE_LOAD_DONE, line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Eina_Bool
|
Eina_Bool
|
||||||
|
|
|
@ -2075,6 +2075,30 @@ _elm_code_widget_show_whitespace_get(Eo *obj EINA_UNUSED, Elm_Code_Widget_Data *
|
||||||
return pd->show_whitespace;
|
return pd->show_whitespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EOLIAN static void
|
||||||
|
_elm_code_widget_syntax_enabled_set(Eo *obj, Elm_Code_Widget_Data *pd EINA_UNUSED,
|
||||||
|
Eina_Bool enabled)
|
||||||
|
{
|
||||||
|
Elm_Code_Widget *widget = obj;
|
||||||
|
Elm_Code *code;
|
||||||
|
|
||||||
|
code = elm_code_widget_code_get(widget);
|
||||||
|
if (enabled)
|
||||||
|
elm_code_parser_standard_add(code, ELM_CODE_PARSER_STANDARD_SYNTAX);
|
||||||
|
else
|
||||||
|
code->parsers = eina_list_remove(code->parsers, ELM_CODE_PARSER_STANDARD_SYNTAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
EOLIAN static Eina_Bool
|
||||||
|
_elm_code_widget_syntax_enabled_get(Eo *obj, Elm_Code_Widget_Data *pd EINA_UNUSED)
|
||||||
|
{
|
||||||
|
Elm_Code_Widget *widget = obj;
|
||||||
|
Elm_Code *code;
|
||||||
|
|
||||||
|
code = elm_code_widget_code_get(widget);
|
||||||
|
return !!eina_list_data_find(code->parsers, ELM_CODE_PARSER_STANDARD_SYNTAX);
|
||||||
|
}
|
||||||
|
|
||||||
EOLIAN static void
|
EOLIAN static void
|
||||||
_elm_code_widget_tab_inserts_spaces_set(Eo *obj EINA_UNUSED, Elm_Code_Widget_Data *pd,
|
_elm_code_widget_tab_inserts_spaces_set(Eo *obj EINA_UNUSED, Elm_Code_Widget_Data *pd,
|
||||||
Eina_Bool spaces)
|
Eina_Bool spaces)
|
||||||
|
|
|
@ -140,7 +140,7 @@ class Elm.Code_Widget (Elm.Layout, Elm.Interface.Atspi.Text)
|
||||||
}
|
}
|
||||||
@property show_whitespace {
|
@property show_whitespace {
|
||||||
set {
|
set {
|
||||||
[[Set where white space should be shown.]]
|
[[Set whether white space should be shown.]]
|
||||||
}
|
}
|
||||||
get {
|
get {
|
||||||
[[Get whether or not white space will be visible.]]
|
[[Get whether or not white space will be visible.]]
|
||||||
|
@ -149,6 +149,17 @@ class Elm.Code_Widget (Elm.Layout, Elm.Interface.Atspi.Text)
|
||||||
show_whitespace: bool; [[Whether or not we show whitespace characters]]
|
show_whitespace: bool; [[Whether or not we show whitespace characters]]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@property syntax_enabled {
|
||||||
|
set {
|
||||||
|
[[Set whether syntax highlighting should be use for this widget.]]
|
||||||
|
}
|
||||||
|
get {
|
||||||
|
[[Get this widget's enabled state for syntax highlighting.]]
|
||||||
|
}
|
||||||
|
values {
|
||||||
|
syntax_enabled: bool; [[Whether or not to enable syntax highlighting]]
|
||||||
|
}
|
||||||
|
}
|
||||||
@property tab_inserts_spaces {
|
@property tab_inserts_spaces {
|
||||||
set {
|
set {
|
||||||
[[Set whether space characters should be inserted instead of tabs.]]
|
[[Set whether space characters should be inserted instead of tabs.]]
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "elementary_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "elm_suite.h"
|
||||||
|
#include "Elementary.h"
|
||||||
|
#include "elm_code_syntax.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
_append_line(Elm_Code_File *file, const char *line)
|
||||||
|
{
|
||||||
|
int length;
|
||||||
|
|
||||||
|
length = strlen(line);
|
||||||
|
elm_code_file_line_append(file, line, length, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_assert_line_token_types(Elm_Code_File *file, unsigned int number,unsigned int count, Elm_Code_Token_Type types[])
|
||||||
|
{
|
||||||
|
Elm_Code_Line *line;
|
||||||
|
unsigned int found, i;
|
||||||
|
|
||||||
|
line = elm_code_file_line_get(file, number);
|
||||||
|
if (line->tokens)
|
||||||
|
found = eina_list_count(line->tokens);
|
||||||
|
else
|
||||||
|
found = 0;
|
||||||
|
ck_assert_msg(found == count, "Bad token count %d on line %d - expected %d", found, number, count);
|
||||||
|
|
||||||
|
for (i = 0; i < found; i++)
|
||||||
|
{
|
||||||
|
Elm_Code_Token *token;
|
||||||
|
|
||||||
|
token = eina_list_nth(line->tokens, i);
|
||||||
|
ck_assert_msg(token->type == types[i], "Token mismatch (%d!=%d) on line %d", token->type, types[i], number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST (elm_code_syntax_lookup)
|
||||||
|
{
|
||||||
|
Elm_Code_Syntax *syntax;
|
||||||
|
|
||||||
|
syntax = elm_code_syntax_for_mime_get("text/x-csrc");
|
||||||
|
ck_assert(!!syntax);
|
||||||
|
syntax = elm_code_syntax_for_mime_get("text/x-chdr");
|
||||||
|
ck_assert(!!syntax);
|
||||||
|
syntax = elm_code_syntax_for_mime_get("text/unknown");
|
||||||
|
ck_assert(!syntax);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST (elm_code_syntax_c)
|
||||||
|
{
|
||||||
|
Elm_Code *code;
|
||||||
|
Elm_Code_File *file;
|
||||||
|
Elm_Code_Widget *widget;
|
||||||
|
Evas_Object *win;
|
||||||
|
|
||||||
|
elm_init(1, NULL);
|
||||||
|
code = elm_code_create();
|
||||||
|
file = elm_code_file_new(code);
|
||||||
|
|
||||||
|
win = elm_win_add(NULL, "syntax", ELM_WIN_BASIC);
|
||||||
|
widget = elm_code_widget_add(win, code);
|
||||||
|
elm_obj_code_widget_code_get(widget)->file->mime = "text/x-csrc";
|
||||||
|
elm_code_widget_syntax_enabled_set(widget, EINA_TRUE);
|
||||||
|
|
||||||
|
_append_line(file, "#include <stdio.h>");
|
||||||
|
_append_line(file, "int main(int argc, char **argv)");
|
||||||
|
_append_line(file, "{");
|
||||||
|
_append_line(file, " // display a welcome greeting");
|
||||||
|
_append_line(file, " if (argc > 0)");
|
||||||
|
_append_line(file, " printf(\"Hello, %s!\\n\", argv[0]);");
|
||||||
|
_append_line(file, " else");
|
||||||
|
_append_line(file, " printf(\"Hello, World!\\n\");");
|
||||||
|
_append_line(file, " return 0;");
|
||||||
|
_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,
|
||||||
|
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,
|
||||||
|
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,
|
||||||
|
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,
|
||||||
|
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,
|
||||||
|
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});
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
|
@ -75,6 +75,7 @@ static const Efl_Test_Case etc[] = {
|
||||||
{ "elm_code_file_load", elm_code_file_test_load },
|
{ "elm_code_file_load", elm_code_file_test_load },
|
||||||
{ "elm_code_file_memory", elm_code_file_test_memory },
|
{ "elm_code_file_memory", elm_code_file_test_memory },
|
||||||
{ "elm_code_parse", elm_code_test_parse },
|
{ "elm_code_parse", elm_code_test_parse },
|
||||||
|
{ "elm_code_syntax", elm_code_test_syntax },
|
||||||
{ "elm_code_text", elm_code_test_text },
|
{ "elm_code_text", elm_code_test_text },
|
||||||
{ "elm_code_indent", elm_code_test_indent },
|
{ "elm_code_indent", elm_code_test_indent },
|
||||||
{ "elm_code_basic", elm_code_test_basic },
|
{ "elm_code_basic", elm_code_test_basic },
|
||||||
|
|
|
@ -75,6 +75,7 @@ void elm_code_file_test_memory(TCase *tc);
|
||||||
void elm_code_test_basic(TCase *tc);
|
void elm_code_test_basic(TCase *tc);
|
||||||
void elm_code_test_line(TCase *tc);
|
void elm_code_test_line(TCase *tc);
|
||||||
void elm_code_test_parse(TCase *tc);
|
void elm_code_test_parse(TCase *tc);
|
||||||
|
void elm_code_test_syntax(TCase *tc);
|
||||||
void elm_code_test_text(TCase *tc);
|
void elm_code_test_text(TCase *tc);
|
||||||
void elm_code_test_indent(TCase *tc);
|
void elm_code_test_indent(TCase *tc);
|
||||||
void elm_code_test_widget(TCase *tc);
|
void elm_code_test_widget(TCase *tc);
|
||||||
|
|
Loading…
Reference in New Issue