#include #include "common.h" #define COLOR_INSERT(strbuf, src, length, cur, prev, cmp, color) \ { \ ret = color_markup_insert((strbuf), (src), (length), (cur), (prev), \ (cmp), (color)); \ if (ret == 1) continue; \ else if (ret == -1) goto finished; \ } \ struct syntax_color_s { Eina_Strbuf *strbuf; Eina_Stringshare *col1; Eina_Stringshare *col2; Eina_Stringshare *col3; Eina_Stringshare *col4; Eina_Stringshare *col5; Ecore_Timer *buf_flush_timer; Eina_Bool enabled : 1; }; Eina_Bool buf_flush_timer_cb(void *data) { color_data *cd = data; /* At this moment, I have no idea the policy of the eina strbuf. If the string buffer wouldn't reduce the buffer size, it needs to prevent the buffer size not to be grown endlessly. */ eina_strbuf_free(cd->strbuf); cd->strbuf = eina_strbuf_new(); return ECORE_CALLBACK_RENEW; } color_data * color_init() { color_data *cd = calloc(1, sizeof(color_data)); cd->strbuf = eina_strbuf_new(); cd->buf_flush_timer = ecore_timer_add(1800, buf_flush_timer_cb, cd); cd->col1 = eina_stringshare_add("424242"); cd->col2 = eina_stringshare_add("a000a0"); cd->col3 = eina_stringshare_add("0000a0"); cd->col4 = eina_stringshare_add("969600"); cd->col5 = eina_stringshare_add("009600"); return cd; } void color_term(color_data *cd) { if (cd->buf_flush_timer) ecore_timer_del(cd->buf_flush_timer); eina_strbuf_free(cd->strbuf); eina_stringshare_del(cd->col1); eina_stringshare_del(cd->col2); eina_stringshare_del(cd->col3); eina_stringshare_del(cd->col4); eina_stringshare_del(cd->col5); free(cd); } static int color_markup_insert(Eina_Strbuf *strbuf, const char **src, int length, char **cur, char **prev, const char *cmp, Eina_Stringshare *color) { char buf[128]; //FIXME: compare opposite case. if (strncmp(*cur, cmp, strlen(cmp))) return 0; eina_strbuf_append_length(strbuf, *prev, *cur - *prev); snprintf(buf, sizeof(buf), "%s", color, cmp); eina_strbuf_append(strbuf, buf); *cur += strlen(cmp); if (*cur > (*src + length)) return -1; *prev = *cur; return 1; } 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(""); if (strncmp(*cur, "", 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) { int cmp_size = 5; //strlen("
"); if (strncmp(*cur, "
", 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 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); 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, "*/"); *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, "*/"); 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); eina_strbuf_append(strbuf, buf); int cmp_size = 2; //strlen("//"); *cur += cmp_size; if (*cur > (*src + length)) { eina_strbuf_append(strbuf, ""); return -1; } *prev = *cur; cmp_size = strlen("
"); *cur = strstr(*prev, "
"); if (*cur) { eina_strbuf_append_length(strbuf, *prev, (*cur - *prev)); eina_strbuf_append(strbuf, "
"); *cur += cmp_size; *prev = *cur; return 1; } eina_strbuf_append(strbuf, *prev); *prev = *cur; eina_strbuf_append(strbuf, ""); 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:
if (br_skip(strbuf, &src, length, &cur, &prev) == 1) continue; //escape EOL: 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; } /* OPTIMIZATION POINT 1. Use Hash 2. Apply Color only changed line. */ const char * color_apply(color_data *cd, const char *src, int length, Eina_Bool realtime) { static Eina_Bool inside_string = EINA_FALSE; static Eina_Bool inside_comment = EINA_FALSE; //workaround code. need to improve it later. if (realtime) { inside_string = EINA_FALSE; inside_comment = EINA_FALSE; } 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; int ret; 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->col5, &inside_comment); if (ret == 1) continue; else if (ret == -1) goto finished; //handle comment: // ret = comment2_apply(strbuf, &src, length, &cur, &prev, cd->col5, &inside_comment); if (ret == 1) continue; else if (ret == -1) goto finished; if (realtime) { //escape string: " ~ " if (!strncmp(cur, """, strlen("""))) { eina_strbuf_append_length(strbuf, prev, cur - prev); eina_strbuf_append(strbuf, """); cur += strlen("""); prev = cur; inside_string = !inside_string; continue; } } else { //escape string: " ~ " if (cur[0] == '\"') { eina_strbuf_append_length(strbuf, prev, cur - prev); eina_strbuf_append_char(strbuf, '\"'); cur++; prev = cur; inside_string = !inside_string; continue; } } if (inside_string || inside_comment) { cur++; continue; } //FIXME: construct from the configuration file //syntax group 1 Eina_Stringshare *col1 = cd->col1; COLOR_INSERT(strbuf, &src, length, &cur, &prev, "{", col1); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "}", col1); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "[", col1); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "]", col1); COLOR_INSERT(strbuf, &src, length, &cur, &prev, ";", col1); COLOR_INSERT(strbuf, &src, length, &cur, &prev, ":", col1); //syntax group 2 Eina_Stringshare *col2 = cd->col2; COLOR_INSERT(strbuf, &src, length, &cur, &prev, "collections", col2); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "description", col2); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "fill", col2); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "group", col2); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "images", col2); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "map", col2); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "origin", col2); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "parts", col2); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "part", col2); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "programs", col2); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "program", col2); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "rel1", col2); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "rel2", col2); //syntax group 3 Eina_Stringshare *col3 = cd->col3; COLOR_INSERT(strbuf, &src, length, &cur, &prev, "action", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "after", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "align", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "aspect", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "border_scale", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "border", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "clip_to", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "color", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "fixed", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "font", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "inherit", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "max", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "min", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "mouse_events", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "name", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "normal", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "on", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "scale", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "signal", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "state", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "relative", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "repeat_events", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "source", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "target", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "to", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "transition", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "type", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "visible", col3); //syntax group 4 Eina_Stringshare *col4 = cd->col4; COLOR_INSERT(strbuf, &src, length, &cur, &prev, "ACCELERATE_FACTOR", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "ACCELERATE", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "BOUNCE", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "BOX", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "COMP", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "DECELERATE_FACTOR", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "DECELERATE", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "DIVISOR_INTERP", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "EXTERNAL", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "GRADIENT", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "GROUP", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "IMAGE", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "LINEAR", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "LOSSY", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "PROXY", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "RAW", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "RECT", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "SINUSOIDAL_FACTOR", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "SINUSOIDAL", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "SPACER", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "SPRING", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "STATE_SET", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "SWALLOW", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "TABLE", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "TEXTBLOCK", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "TEXT", col4); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "USER", col4); //duplicated groups 1 COLOR_INSERT(strbuf, &src, length, &cur, &prev, "image:", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "size:", col3); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "text:", col3); //duplicated groups 2 COLOR_INSERT(strbuf, &src, length, &cur, &prev, "image", col2); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "text", col2); COLOR_INSERT(strbuf, &src, length, &cur, &prev, "size", col2); 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; }