forked from enlightenment/enventor
600 lines
14 KiB
C
600 lines
14 KiB
C
#include <Elementary.h>
|
|
#include "common.h"
|
|
|
|
#define COL_NUM 6
|
|
|
|
typedef struct color_tuple
|
|
{
|
|
Eina_Stringshare *key;
|
|
Eina_Stringshare *col;
|
|
} color_tuple;
|
|
|
|
typedef struct color
|
|
{
|
|
char *val;
|
|
Eina_List *keys;
|
|
} color;
|
|
|
|
typedef struct syntax_color_group
|
|
{
|
|
char *comment;
|
|
char *define;
|
|
color colors[COL_NUM];
|
|
} syntax_color_group;
|
|
|
|
struct syntax_color_s
|
|
{
|
|
Eina_Strbuf *strbuf;
|
|
Eina_Strbuf *cachebuf;
|
|
Eina_Hash *color_hash;
|
|
Eina_Stringshare *col_comment;
|
|
Eina_Stringshare *col_define;
|
|
Eina_Stringshare *cols[COL_NUM];
|
|
syntax_color_group *scg;
|
|
};
|
|
|
|
static Eet_Data_Descriptor *edd_scg = NULL;
|
|
static Eet_Data_Descriptor *edd_color = NULL;
|
|
|
|
static void
|
|
hash_free_cb(void *data)
|
|
{
|
|
Eina_Inarray *inarray = data;
|
|
color_tuple *tuple;
|
|
EINA_INARRAY_FOREACH(inarray, tuple)
|
|
eina_stringshare_del(tuple->key);
|
|
eina_inarray_free(inarray);
|
|
}
|
|
|
|
static void
|
|
eddc_init()
|
|
{
|
|
Eet_Data_Descriptor_Class eddc;
|
|
eet_eina_stream_data_descriptor_class_set(&eddc, sizeof(eddc),
|
|
"syntax_color_group",
|
|
sizeof(syntax_color_group));
|
|
edd_scg = eet_data_descriptor_stream_new(&eddc);
|
|
|
|
eet_eina_stream_data_descriptor_class_set(&eddc, sizeof(eddc), "color",
|
|
sizeof(color));
|
|
edd_color = eet_data_descriptor_stream_new(&eddc);
|
|
|
|
EET_DATA_DESCRIPTOR_ADD_BASIC(edd_scg, syntax_color_group, "comment",
|
|
comment, EET_T_STRING);
|
|
EET_DATA_DESCRIPTOR_ADD_BASIC(edd_scg, syntax_color_group, "define",
|
|
define, EET_T_STRING);
|
|
|
|
EET_DATA_DESCRIPTOR_ADD_BASIC(edd_color, color, "val", val, EET_T_STRING);
|
|
EET_DATA_DESCRIPTOR_ADD_LIST_STRING(edd_color, color, "keys", keys);
|
|
|
|
EET_DATA_DESCRIPTOR_ADD_ARRAY(edd_scg, syntax_color_group, "colors",
|
|
colors, edd_color);
|
|
}
|
|
|
|
static void
|
|
eddc_term()
|
|
{
|
|
eet_data_descriptor_free(edd_scg);
|
|
eet_data_descriptor_free(edd_color);
|
|
}
|
|
|
|
static void
|
|
color_load(color_data *cd)
|
|
{
|
|
char buf[PATH_MAX];
|
|
snprintf(buf, sizeof(buf), "%s/color/color.eet", elm_app_data_dir_get());
|
|
|
|
Eet_File *ef = eet_open(buf, EET_FILE_MODE_READ);
|
|
if (ef)
|
|
{
|
|
cd->scg = eet_data_read(ef, edd_scg, "color");
|
|
if (!cd->scg) EINA_LOG_ERR("Failed to read syntax color group.");
|
|
eet_close(ef);
|
|
}
|
|
else EINA_LOG_ERR("Failed to open color data file \"%s\"", buf);
|
|
}
|
|
|
|
static void
|
|
color_table_init(color_data *cd)
|
|
{
|
|
color_tuple *tuple;
|
|
int i;
|
|
Eina_List *l;
|
|
char *key;
|
|
char tmp[2];
|
|
Eina_Inarray *inarray;
|
|
syntax_color_group *scg = cd->scg;
|
|
|
|
if (!scg) return;
|
|
|
|
cd->col_comment = eina_stringshare_add(scg->comment);
|
|
//free(scg->comment);
|
|
cd->col_define = eina_stringshare_add(scg->define);
|
|
//free(scg->define);
|
|
|
|
cd->color_hash = eina_hash_string_small_new(hash_free_cb);
|
|
|
|
for (i = 0; i < COL_NUM; i++)
|
|
{
|
|
cd->cols[i] = eina_stringshare_add(scg->colors[i].val);
|
|
//free(scg->colors[i].val);
|
|
|
|
EINA_LIST_FOREACH(scg->colors[i].keys, l, key)
|
|
{
|
|
tmp[0] = key[0];
|
|
tmp[1] = '\0';
|
|
|
|
inarray = eina_hash_find(cd->color_hash, tmp);
|
|
if (!inarray)
|
|
{
|
|
inarray = eina_inarray_new(sizeof(color_tuple), 0);
|
|
eina_hash_add(cd->color_hash, tmp, inarray);
|
|
}
|
|
|
|
tuple = malloc(sizeof(color_tuple));
|
|
tuple->col = cd->cols[i];
|
|
tuple->key = eina_stringshare_add(key);
|
|
//free(key);
|
|
eina_inarray_push(inarray, tuple);
|
|
}
|
|
eina_list_free(scg->colors[i].keys);
|
|
}
|
|
|
|
free(scg);
|
|
cd->scg = NULL;
|
|
}
|
|
|
|
color_data *
|
|
color_init(Eina_Strbuf *strbuf)
|
|
{
|
|
color_data *cd = malloc(sizeof(color_data));
|
|
cd->strbuf = strbuf;
|
|
cd->cachebuf = eina_strbuf_new();
|
|
|
|
eddc_init();
|
|
color_load(cd);
|
|
eddc_term();
|
|
|
|
color_table_init(cd);
|
|
|
|
return cd;
|
|
}
|
|
|
|
void
|
|
color_term(color_data *cd)
|
|
{
|
|
eina_hash_free(cd->color_hash);
|
|
eina_strbuf_free(cd->cachebuf);
|
|
|
|
eina_stringshare_del(cd->col_comment);
|
|
eina_stringshare_del(cd->col_define);
|
|
|
|
int i;
|
|
for(i = 0; i < COL_NUM; i++)
|
|
eina_stringshare_del(cd->cols[i]);
|
|
|
|
free(cd);
|
|
}
|
|
|
|
static Eina_Bool
|
|
color_markup_insert(Eina_Strbuf *strbuf, const char **src, int length,
|
|
char **cur, char **prev, const char *cmp,
|
|
Eina_Stringshare *color)
|
|
{
|
|
char buf[128];
|
|
|
|
eina_strbuf_append_length(strbuf, *prev, *cur - *prev);
|
|
snprintf(buf, sizeof(buf), "<color=#%s>%s</color>", color, cmp);
|
|
eina_strbuf_append(strbuf, buf);
|
|
*cur += strlen(cmp);
|
|
if (*cur > (*src + length)) return EINA_FALSE;
|
|
*prev = *cur;
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static int
|
|
markup_skip(Eina_Strbuf *strbuf, const char **src, int length, char **cur,
|
|
char **prev)
|
|
{
|
|
if ((*cur)[0] != '<') return 0;
|
|
|
|
eina_strbuf_append_length(strbuf, *prev, (*cur - *prev));
|
|
(*cur)++;
|
|
|
|
if (*cur > (*src + length)) return -1;
|
|
*prev = *cur;
|
|
|
|
*cur = strchr(*prev, '>');
|
|
|
|
if (*cur)
|
|
{
|
|
(*cur)++;
|
|
*prev = *cur;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
*prev = *cur;
|
|
return -1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
tab_skip(Eina_Strbuf *strbuf, const char **src, int length, char **cur,
|
|
char **prev)
|
|
{
|
|
int cmp_size = 6; //strlen("<tab/>");
|
|
if (strncmp(*cur, "<tab/>", cmp_size)) return 0;
|
|
eina_strbuf_append_length(strbuf, *prev, (*cur - *prev + cmp_size));
|
|
*cur += cmp_size;
|
|
if (*cur > (*src + length)) return -1;
|
|
*prev = *cur;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
br_skip(Eina_Strbuf *strbuf, const char **src, int length, char **cur,
|
|
char **prev)
|
|
{
|
|
if (strncmp(*cur, EOL, EOL_LEN)) return 0;
|
|
eina_strbuf_append_length(strbuf, *prev, (*cur - *prev + EOL_LEN));
|
|
*cur += EOL_LEN;
|
|
if (*cur > (*src + length)) return -1;
|
|
*prev = *cur;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
comment_apply(Eina_Strbuf *strbuf, const char **src, int length, char **cur,
|
|
char **prev, const Eina_Stringshare *color,
|
|
Eina_Bool *inside_comment)
|
|
{
|
|
if (!(*inside_comment))
|
|
{
|
|
if ((*cur)[0] != '/') return 0;
|
|
if ((*cur) + 1 > ((*src) + length)) return -1;
|
|
if ((*cur)[1] != '*') return 0;
|
|
|
|
eina_strbuf_append_length(strbuf, *prev, (*cur - *prev));
|
|
|
|
char buf[128];
|
|
snprintf(buf, sizeof(buf), "<color=#%s>/*", color);
|
|
eina_strbuf_append(strbuf, buf);
|
|
|
|
int cmp_size = 2; //strlen("/*");
|
|
|
|
*cur += cmp_size;
|
|
|
|
if (*cur > (*src + length))
|
|
{
|
|
*inside_comment = EINA_TRUE;
|
|
return -1;
|
|
}
|
|
|
|
*prev = *cur;
|
|
|
|
*cur = strstr(*prev, "*/");
|
|
|
|
if (*cur)
|
|
{
|
|
eina_strbuf_append_length(strbuf, *prev, (*cur - *prev));
|
|
eina_strbuf_append(strbuf, "*/</color>");
|
|
*cur += cmp_size;
|
|
*prev = *cur;
|
|
return 0;
|
|
}
|
|
|
|
eina_strbuf_append(strbuf, *prev);
|
|
*prev = *cur;
|
|
|
|
*inside_comment = EINA_TRUE;
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
if ((*cur)[0] != '*') return 0;
|
|
if ((*cur) + 1 > ((*src) + length)) return -1;
|
|
if ((*cur)[1] != '/') return 0;
|
|
|
|
eina_strbuf_append_length(strbuf, *prev, (*cur - *prev));
|
|
eina_strbuf_append(strbuf, "*/</color>");
|
|
|
|
int cmp_size = 2; //strlen("*/");
|
|
|
|
*cur += cmp_size;
|
|
*inside_comment = EINA_FALSE;
|
|
|
|
if (*cur > (*src + length)) return -1;
|
|
*prev = *cur;
|
|
return 1;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
comment2_apply(Eina_Strbuf *strbuf, const char **src, int length, char **cur,
|
|
char **prev, const Eina_Stringshare *color,
|
|
Eina_Bool *inside_comment)
|
|
{
|
|
if (*inside_comment) return 0;
|
|
if ((*cur)[0] != '/') return 0;
|
|
if (((*cur) + 1) > ((*src) + length)) return -1;
|
|
if ((*cur)[1] != '/') return 0;
|
|
|
|
eina_strbuf_append_length(strbuf, *prev, (*cur - *prev));
|
|
|
|
char buf[128];
|
|
snprintf(buf, sizeof(buf), "<color=#%s>//", color);
|
|
eina_strbuf_append(strbuf, buf);
|
|
|
|
int cmp_size = 2; //strlen("//");
|
|
*cur += cmp_size;
|
|
|
|
if (*cur > (*src + length))
|
|
{
|
|
eina_strbuf_append(strbuf, "</color>");
|
|
return -1;
|
|
}
|
|
|
|
*prev = *cur;
|
|
|
|
*cur = strstr(*prev, EOL);
|
|
|
|
if (*cur)
|
|
{
|
|
eina_strbuf_append_length(strbuf, *prev, (*cur - *prev));
|
|
eina_strbuf_append(strbuf, "</color><br/>");
|
|
*cur += EOL_LEN;
|
|
*prev = *cur;
|
|
return 1;
|
|
}
|
|
|
|
eina_strbuf_append(strbuf, *prev);
|
|
*prev = *cur;
|
|
|
|
eina_strbuf_append(strbuf, "</color>");
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
sharp_apply(Eina_Strbuf *strbuf, const char **src, int length, char **cur,
|
|
char **prev, const Eina_Stringshare *color)
|
|
{
|
|
if ((*cur)[0] != '#') return 0;
|
|
|
|
eina_strbuf_append_length(strbuf, *prev, (*cur - *prev));
|
|
|
|
char buf[128];
|
|
snprintf(buf, sizeof(buf), "<color=#%s>#", color);
|
|
eina_strbuf_append(strbuf, buf);
|
|
|
|
int cmp_size = 1; //strlen("#");
|
|
*cur += cmp_size;
|
|
|
|
if (*cur > (*src + length))
|
|
{
|
|
eina_strbuf_append(strbuf, "</color>");
|
|
return -1;
|
|
}
|
|
|
|
*prev = *cur;
|
|
|
|
char *space = strstr(*prev, " ");
|
|
char *eol = strstr(*prev, EOL);
|
|
|
|
if (space < eol)
|
|
{
|
|
*cur = space;
|
|
cmp_size = 1; //strlen(" ");
|
|
}
|
|
else
|
|
{
|
|
*cur = eol;
|
|
cmp_size = EOL_LEN;
|
|
}
|
|
|
|
if (*cur)
|
|
{
|
|
eina_strbuf_append_length(strbuf, *prev, (*cur - *prev));
|
|
if (space < eol) eina_strbuf_append(strbuf, "</color> ");
|
|
else eina_strbuf_append(strbuf, "</color><br/>");
|
|
*cur += cmp_size;
|
|
*prev = *cur;
|
|
return 1;
|
|
}
|
|
|
|
eina_strbuf_append(strbuf, *prev);
|
|
*prev = *cur;
|
|
|
|
eina_strbuf_append(strbuf, "</color>");
|
|
return -1;
|
|
}
|
|
|
|
const char *
|
|
color_cancel(color_data *cd, const char *src, int length)
|
|
{
|
|
if (!src || length < 1) return NULL;
|
|
Eina_Strbuf *strbuf = cd->strbuf;
|
|
eina_strbuf_reset(strbuf);
|
|
|
|
const char *str = NULL;
|
|
char *prev = (char *) src;
|
|
char *cur = (char *) src;
|
|
|
|
while (cur && (cur <= (src + length)))
|
|
{
|
|
//escape EOL: <br/>
|
|
if (br_skip(strbuf, &src, length, &cur, &prev) == 1)
|
|
continue;
|
|
|
|
//escape EOL: <tab/>
|
|
if (tab_skip(strbuf, &src, length, &cur, &prev) == 1)
|
|
continue;
|
|
|
|
//escape markups: <..> ~ </..>
|
|
if (markup_skip(strbuf, &src, length, &cur, &prev) == 1)
|
|
continue;
|
|
|
|
cur++;
|
|
}
|
|
|
|
//Same with origin source.
|
|
if (prev == src)
|
|
str = src;
|
|
//Some color syntax is applied.
|
|
else
|
|
{
|
|
//append leftovers.
|
|
if (prev + 1 < cur) eina_strbuf_append(strbuf, prev);
|
|
str = eina_strbuf_string_get(strbuf);
|
|
}
|
|
return str;
|
|
}
|
|
|
|
static int
|
|
bracket_escape(Eina_Strbuf *strbuf, char **cur, char **prev)
|
|
{
|
|
if ((*cur)[0] != '&') return 0;
|
|
int cmp_size = 4;
|
|
|
|
if (!strncmp(*cur, "<", cmp_size))
|
|
{
|
|
eina_strbuf_append_length(strbuf, *prev, *cur - *prev);
|
|
eina_strbuf_append(strbuf, "<");
|
|
*cur += cmp_size;
|
|
*prev = *cur;
|
|
return 1;
|
|
}
|
|
else if (!strncmp(*cur, ">", cmp_size))
|
|
{
|
|
eina_strbuf_append_length(strbuf, *prev, *cur - *prev);
|
|
eina_strbuf_append(strbuf, ">");
|
|
*cur += cmp_size;
|
|
*prev = *cur;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
OPTIMIZATION POINT
|
|
1. Apply Color only changed line.
|
|
*/
|
|
const char *
|
|
color_apply(color_data *cd, const char *src, int length)
|
|
{
|
|
Eina_Bool inside_string = EINA_FALSE;
|
|
Eina_Bool inside_comment = EINA_FALSE;
|
|
|
|
if (!src || (length < 1)) return NULL;
|
|
|
|
Eina_Strbuf *strbuf = cd->cachebuf;
|
|
eina_strbuf_reset(strbuf);
|
|
|
|
const char *str = NULL;
|
|
char *prev = (char *) src;
|
|
char *cur = (char *) src;
|
|
int ret;
|
|
Eina_Inarray *inarray;
|
|
color_tuple *tuple;
|
|
|
|
while (cur && (cur <= (src + length)))
|
|
{
|
|
//escape empty string
|
|
if (cur[0] == ' ')
|
|
{
|
|
eina_strbuf_append_length(strbuf, prev, cur - prev);
|
|
eina_strbuf_append_char(strbuf, ' ');
|
|
++cur;
|
|
prev = cur;
|
|
continue;
|
|
}
|
|
|
|
//handle comment: /* ~ */
|
|
ret = comment_apply(strbuf, &src, length, &cur, &prev, cd->col_comment,
|
|
&inside_comment);
|
|
if (ret == 1) continue;
|
|
else if (ret == -1) goto finished;
|
|
|
|
//handle comment: //
|
|
ret = comment2_apply(strbuf, &src, length, &cur, &prev, cd->col_comment,
|
|
&inside_comment);
|
|
if (ret == 1) continue;
|
|
else if (ret == -1) goto finished;
|
|
|
|
//escape string: " ~ "
|
|
if (cur[0] == QUOT_C)
|
|
{
|
|
eina_strbuf_append_length(strbuf, prev, cur - prev);
|
|
eina_strbuf_append_char(strbuf, QUOT_C);
|
|
cur++;
|
|
prev = cur;
|
|
inside_string = !inside_string;
|
|
continue;
|
|
}
|
|
if (inside_string || inside_comment)
|
|
{
|
|
cur++;
|
|
continue;
|
|
}
|
|
|
|
//FIXME: This might be textblock problem. should be removed here.
|
|
//escape <> bracket.
|
|
ret = bracket_escape(strbuf, &cur, &prev);
|
|
if (ret == 1) continue;
|
|
|
|
//handle comment: #
|
|
ret = sharp_apply(strbuf, &src, length, &cur, &prev, cd->col_define);
|
|
if (ret == 1) continue;
|
|
else if (ret == -1) goto finished;
|
|
|
|
char key[2];
|
|
key[0] = cur[0];
|
|
key[1] = '\0';
|
|
inarray = eina_hash_find(cd->color_hash, key);
|
|
|
|
//Found tuple list. Search in detail.
|
|
if (inarray)
|
|
{
|
|
Eina_Bool found = EINA_FALSE;
|
|
|
|
EINA_INARRAY_FOREACH(inarray, tuple)
|
|
{
|
|
if (!strncmp(cur, tuple->key, strlen(tuple->key)))
|
|
{
|
|
ret = color_markup_insert(strbuf, &src, length, &cur,
|
|
&prev, tuple->key, tuple->col);
|
|
if (ret)
|
|
{
|
|
found = EINA_TRUE;
|
|
break;
|
|
}
|
|
else goto finished;
|
|
}
|
|
}
|
|
if (found) continue;
|
|
}
|
|
cur++;
|
|
}
|
|
|
|
//Same with origin source.
|
|
if (prev == src)
|
|
str = src;
|
|
//Some color syntax is applied.
|
|
else
|
|
{
|
|
finished:
|
|
//append leftovers.
|
|
if (prev + 1 < cur) eina_strbuf_append(strbuf, prev);
|
|
str = eina_strbuf_string_get(strbuf);
|
|
}
|
|
|
|
return str;
|
|
}
|