diff options
| author | Albert Cervin <albert@acervin.com> | 2024-01-31 23:24:02 +0100 |
|---|---|---|
| committer | Albert Cervin <albert@acervin.com> | 2024-01-31 23:24:02 +0100 |
| commit | 4b6933a7cb5e0ef583071fffc0c97b829e72c684 (patch) | |
| tree | cb608d7d3929fd1a32010b11be751fe2b741eeee /src/dged | |
| parent | ef64c4d05794484e5affbf633f095877cc1422df (diff) | |
| download | dged-4b6933a7cb5e0ef583071fffc0c97b829e72c684.tar.gz dged-4b6933a7cb5e0ef583071fffc0c97b829e72c684.tar.xz dged-4b6933a7cb5e0ef583071fffc0c97b829e72c684.zip | |
Fix syntax predicate creation
It is now created when parsing the queries.
Also, make completion popup directly.
Diffstat (limited to 'src/dged')
| -rw-r--r-- | src/dged/location.c | 32 | ||||
| -rw-r--r-- | src/dged/minibuffer.c | 20 | ||||
| -rw-r--r-- | src/dged/syntax.c | 273 | ||||
| -rw-r--r-- | src/dged/text.c | 8 |
4 files changed, 157 insertions, 176 deletions
diff --git a/src/dged/location.c b/src/dged/location.c index cac0333..0c7e973 100644 --- a/src/dged/location.c +++ b/src/dged/location.c @@ -2,25 +2,19 @@ bool location_is_between(struct location location, struct location start, struct location end) { - if (location.line >= start.line && location.line <= end.line) { - if (location.line == end.line && location.col <= end.col && - location.line == start.line && location.col >= start.col) { - // only one line - return true; - } else if (location.line == start.line && location.line != end.line && - location.col >= start.col) { - // we are on the first line - return true; - } else if (location.line == end.line && location.line != start.line && - location.col <= end.col) { - // we are on the last line - return true; - } else if (location.line != end.line && location.line != start.line) { - // we are on lines in between - return true; - } - } - return false; + return (location.line >= start.line && location.line <= end.line) && + ( + // inbetween + (location.line != end.line && location.line != start.line) || + // first line + (location.line == start.line && location.line != end.line && + location.col >= start.col) || + // last line + (location.line == end.line && location.line != start.line && + location.col <= end.col) || + // only one line + (location.line == end.line && location.col <= end.col && + location.line == start.line && location.col >= start.col)); } int location_compare(struct location l1, struct location l2) { diff --git a/src/dged/minibuffer.c b/src/dged/minibuffer.c index 634a864..bbe80ed 100644 --- a/src/dged/minibuffer.c +++ b/src/dged/minibuffer.c @@ -18,7 +18,6 @@ static struct minibuffer { char prompt[128]; struct command_ctx prompt_command_ctx; bool prompt_active; - bool clear; struct window *prev_window; struct buffer *message_buffer; @@ -65,9 +64,9 @@ int32_t minibuffer_execute() { } } - minibuffer_abort_prompt(); int32_t res = execute_command(c->self, c->commands, c->active_window, c->buffers, argc, (const char **)argv); + minibuffer_abort_prompt(); free(l); @@ -81,10 +80,8 @@ void update(struct buffer *buffer, void *userdata) { struct timespec current; struct minibuffer *mb = (struct minibuffer *)userdata; clock_gettime(CLOCK_MONOTONIC, ¤t); - if ((!mb->prompt_active && current.tv_sec >= mb->expires.tv_sec) || - mb->clear) { - buffer_clear(buffer); - mb->clear = false; + if ((!mb->prompt_active && current.tv_sec >= mb->expires.tv_sec)) { + minibuffer_clear(); } } @@ -96,7 +93,6 @@ void minibuffer_init(struct buffer *buffer, struct buffers *buffers) { g_minibuffer.buffer = buffer; g_minibuffer.expires.tv_sec = 0; g_minibuffer.expires.tv_nsec = 0; - g_minibuffer.clear = false; g_minibuffer.prompt_active = false; buffer_add_update_hook(g_minibuffer.buffer, update, &g_minibuffer); @@ -111,7 +107,6 @@ void echo(uint32_t timeout, const char *fmt, va_list args) { clock_gettime(CLOCK_MONOTONIC, &g_minibuffer.expires); g_minibuffer.expires.tv_sec += timeout; - g_minibuffer.clear = false; static char buff[2048]; size_t nbytes = vsnprintf(buff, 2048, fmt, args); @@ -188,17 +183,12 @@ static void minibuffer_setup(struct command_ctx command_ctx, windows_set_active(minibuffer_window()); } + minibuffer_clear(); if (initial != NULL) { buffer_set_text(g_minibuffer.buffer, (uint8_t *)initial, strlen(initial)); - // there might be an earlier clear request but - // we have sort of taken care of that here - g_minibuffer.clear = false; - // TODO: what to do with these buffer_view_goto_end_of_line(window_buffer_view(minibuffer_window())); - } else { - minibuffer_clear(); } } @@ -259,7 +249,7 @@ bool minibuffer_displaying() { void minibuffer_clear() { g_minibuffer.expires.tv_sec = 0; g_minibuffer.expires.tv_nsec = 0; - g_minibuffer.clear = true; + buffer_clear(g_minibuffer.buffer); } bool minibuffer_focused() { return g_minibuffer.prompt_active; } diff --git a/src/dged/syntax.c b/src/dged/syntax.c index 5f94d60..0935080 100644 --- a/src/dged/syntax.c +++ b/src/dged/syntax.c @@ -15,7 +15,6 @@ #include "buffer.h" #include "display.h" #include "hash.h" -#include "hashmap.h" #include "minibuffer.h" #include "path.h" #include "text.h" @@ -26,13 +25,41 @@ static bool treesitter_path_allocated = false; static const char *parser_filename = "parser"; static const char *highlight_path = "queries/highlights.scm"; -HASHMAP_ENTRY_TYPE(re_cache_entry, regex_t); +// TODO: move to own file +#define s8(s) ((struct s8){s, strlen(s)}) + +struct s8 { + char *s; + uint32_t l; +}; + +static bool s8eq(struct s8 s1, struct s8 s2) { + return s1.l == s2.l && memcmp(s1.s, s2.s, s1.l) == 0; +} + +static char *s8tocstr(struct s8 s) { + char *cstr = (char *)malloc(s.l + 1); + memcpy(cstr, s.s, s.l); + cstr[s.l] = '\0'; + return cstr; +} + +struct predicate { + uint32_t pattern_idx; + + bool (*eval)(struct s8, uint32_t, struct s8[], struct s8, void *); + uint32_t argc; + struct s8 argv[32]; + void *data; + + void (*cleanup)(void *); +}; struct highlight { TSParser *parser; TSTree *tree; TSQuery *query; - HASHMAP(struct re_cache_entry) re_cache; + VEC(struct predicate) predicates; void *dlhandle; }; @@ -43,11 +70,13 @@ static void delete_parser(struct buffer *buffer, void *userdata) { ts_query_delete(highlight->query); } - HASHMAP_FOR_EACH(&highlight->re_cache, struct re_cache_entry * entry) { - regfree(&entry->value); + VEC_FOR_EACH(&highlight->predicates, struct predicate * p) { + if (p->cleanup != NULL) { + p->cleanup(p->data); + } } - HASHMAP_DESTROY(&highlight->re_cache); + VEC_DESTROY(&highlight->predicates); ts_tree_delete(highlight->tree); ts_parser_delete(highlight->parser); @@ -101,6 +130,78 @@ static const char *lang_folder(struct buffer *buffer) { return fld; } +static bool eval_match(struct s8 capname, uint32_t argc, struct s8 argv[], + struct s8 value, void *data) { + regex_t *regex = (regex_t *)data; + if (regex == NULL) { + return false; + } + + char *text = s8tocstr(value); + bool match = regexec(regex, text, 0, NULL, 0) == 0; + + free(text); + return match; +} + +static void cleanup_match(void *data) { + regex_t *regex = (regex_t *)data; + if (regex != NULL) { + regfree(regex); + free(regex); + } +} + +static void create_predicates(struct highlight *h, uint32_t pattern_index) { + uint32_t npreds = 0; + const TSQueryPredicateStep *predicate_steps = + ts_query_predicates_for_pattern(h->query, pattern_index, &npreds); + + struct s8 capname; + struct s8 args[32] = {0}; + uint32_t argc = 0; + for (uint32_t predi = 0; predi < npreds; ++predi) { + const TSQueryPredicateStep *step = &predicate_steps[predi]; + switch (step->type) { + case TSQueryPredicateStepTypeCapture: + capname.s = (char *)ts_query_capture_name_for_id(h->query, step->value_id, + &capname.l); + break; + + case TSQueryPredicateStepTypeString: + args[argc].s = (char *)ts_query_string_value_for_id( + h->query, step->value_id, &args[argc].l); + ++argc; + break; + + case TSQueryPredicateStepTypeDone: + if (s8eq(args[0], s8("match?"))) { + regex_t *re = calloc(1, sizeof(regex_t)); + char *val = s8tocstr(args[1]); + + if (regcomp(re, val, 0) == 0) { + VEC_APPEND(&h->predicates, struct predicate * pred); + pred->pattern_idx = pattern_index; + pred->eval = eval_match; + pred->cleanup = cleanup_match; + pred->argc = 1; + pred->data = re; + + memset(pred->argv, 0, sizeof(struct s8) * 32); + memcpy(pred->argv, args, sizeof(struct s8)); + } else { + free(re); + } + + free(val); + } + + argc = 0; + break; + } + } +} + static TSQuery *setup_queries(const char *lang_root, TSTree *tree) { const char *filename = join_path(lang_root, highlight_path); @@ -150,123 +251,28 @@ static TSQuery *setup_queries(const char *lang_root, TSTree *tree) { return q; } -#define s8(s) ((struct s8){s, strlen(s)}) - -struct s8 { - char *s; - uint32_t l; -}; - -static bool s8eq(struct s8 s1, struct s8 s2) { - return s1.l == s2.l && memcmp(s1.s, s2.s, s1.l) == 0; -} - -char *s8tocstr(struct s8 s) { - char *cstr = (char *)malloc(s.l + 1); - memcpy(cstr, s.s, s.l); - cstr[s.l] = '\0'; - return cstr; -} - -static bool eval_match(struct s8 capname, uint32_t argc, struct s8 argv[], - struct s8 value, void *data) { - regex_t *regex = (regex_t *)data; - if (regex == NULL) { - return false; - } - - char *text = s8tocstr(value); - bool match = regexec(regex, text, 0, NULL, 0) == 0; - - free(text); - return match; -} - -static void cleanup_match(void *data) { - regex_t *regex = (regex_t *)data; - if (regex != NULL) { - regfree(regex); - free(regex); - } -} - -struct predicate { - bool (*fn)(struct s8, uint32_t, struct s8[], struct s8, void *); - void (*cleanup)(void *); - uint32_t argc; - struct s8 argv[32]; - void *data; -}; - -typedef VEC(struct predicate) predicate_vec; - -static regex_t *compile_re_cached(struct highlight *h, struct s8 expr) { - char *val = s8tocstr(expr); - HASHMAP_GET(&h->re_cache, struct re_cache_entry, val, regex_t * re); - if (re == NULL) { - regex_t new_re; - if (regcomp(&new_re, val, 0) == 0) { - HASHMAP_APPEND(&h->re_cache, struct re_cache_entry, val, - struct re_cache_entry * new); - if (new != NULL) { - new->value = new_re; - re = &new->value; +static bool eval_predicates(struct highlight *h, struct text *text, + TSPoint start, TSPoint end, uint32_t pattern_index, + struct s8 cname) { + VEC_FOR_EACH(&h->predicates, struct predicate * p) { + if (p->pattern_idx == pattern_index) { + struct text_chunk txt = + text_get_region(text, start.row, start.column, end.row, end.column); + bool result = + p->eval(cname, p->argc, p->argv, + (struct s8){.s = txt.text, .l = txt.nbytes}, p->data); + + if (txt.allocated) { + free(txt.text); } - } - } - free(val); - return re; -} - -static predicate_vec create_predicates(struct highlight *h, - uint32_t pattern_index) { - predicate_vec predicates; - - uint32_t npreds = 0; - const TSQueryPredicateStep *predicate_steps = - ts_query_predicates_for_pattern(h->query, pattern_index, &npreds); - - VEC_INIT(&predicates, 8); - - bool result = true; - struct s8 capname; - struct s8 args[32] = {0}; - uint32_t argc = 0; - for (uint32_t predi = 0; predi < npreds; ++predi) { - const TSQueryPredicateStep *step = &predicate_steps[predi]; - switch (step->type) { - case TSQueryPredicateStepTypeCapture: - capname.s = (char *)ts_query_capture_name_for_id(h->query, step->value_id, - &capname.l); - break; - - case TSQueryPredicateStepTypeString: - args[argc].s = (char *)ts_query_string_value_for_id( - h->query, step->value_id, &args[argc].l); - ++argc; - break; - - case TSQueryPredicateStepTypeDone: - if (s8eq(args[0], s8("match?"))) { - VEC_APPEND(&predicates, struct predicate * pred); - pred->fn = eval_match; - pred->cleanup = NULL; - pred->argc = 1; - - // cache the regex - pred->data = compile_re_cached(h, args[1]); - - memset(pred->argv, 0, sizeof(struct s8) * 32); - memcpy(pred->argv, args, sizeof(struct s8)); + if (!result) { + return false; } - - argc = 0; - break; } } - return predicates; + return true; } static void update_parser(struct buffer *buffer, void *userdata, @@ -284,7 +290,6 @@ static void update_parser(struct buffer *buffer, void *userdata, } // take results and set text properties - // TODO: can reuse the cursor TSQueryCursor *cursor = ts_query_cursor_new(); uint32_t end_line = origin.line + height >= buffer_num_lines(buffer) ? buffer_num_lines(buffer) - 1 @@ -296,8 +301,6 @@ static void update_parser(struct buffer *buffer, void *userdata, TSQueryMatch match; while (ts_query_cursor_next_match(cursor, &match)) { - predicate_vec predicates = create_predicates(h, match.pattern_index); - for (uint32_t capi = 0; capi < match.capture_count; ++capi) { const TSQueryCapture *cap = &match.captures[capi]; TSPoint start = ts_node_start_point(cap->node); @@ -307,20 +310,8 @@ static void update_parser(struct buffer *buffer, void *userdata, cname.s = (char *)ts_query_capture_name_for_id(h->query, cap->index, &cname.l); - bool predicates_match = true; - VEC_FOR_EACH(&predicates, struct predicate * pred) { - struct text_chunk txt = text_get_region( - buffer->text, start.row, start.column, end.row, end.column); - predicates_match &= - pred->fn(cname, pred->argc, pred->argv, - (struct s8){.s = txt.text, .l = txt.nbytes}, pred->data); - - if (txt.allocated) { - free(txt.text); - } - } - - if (!predicates_match) { + if (!eval_predicates(h, buffer->text, start, end, match.pattern_index, + cname)) { continue; } @@ -388,13 +379,6 @@ static void update_parser(struct buffer *buffer, void *userdata, }, }); } - - VEC_FOR_EACH(&predicates, struct predicate * pred) { - if (pred->cleanup != NULL) { - pred->cleanup(pred->data); - } - } - VEC_DESTROY(&predicates); } ts_query_cursor_delete(cursor); @@ -520,8 +504,13 @@ static void create_parser(struct buffer *buffer, void *userdata) { }; hl->tree = ts_parser_parse(hl->parser, NULL, i); hl->query = setup_queries(lang_root, hl->tree); + + VEC_INIT(&hl->predicates, 8); + uint32_t npatterns = ts_query_pattern_count(hl->query); + for (uint32_t pi = 0; pi < npatterns; ++pi) { + create_predicates(hl, pi); + } hl->dlhandle = h; - HASHMAP_INIT(&hl->re_cache, 64, hash_name); free((void *)lang_root); diff --git a/src/dged/text.c b/src/dged/text.c index bc2b1fc..30036a0 100644 --- a/src/dged/text.c +++ b/src/dged/text.c @@ -184,10 +184,18 @@ void insert_at(struct text *text, uint32_t line, uint32_t col, uint8_t *data, } uint32_t text_line_length(struct text *text, uint32_t lineidx) { + if (lineidx >= text_num_lines(text)) { + return 0; + } + return text->lines[lineidx].nchars; } uint32_t text_line_size(struct text *text, uint32_t lineidx) { + if (lineidx >= text_num_lines(text)) { + return 0; + } + return text->lines[lineidx].nbytes; } |
