From 17c8ded3af09cbb91c62b86be701fcfe3a1ad5de Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Thu, 29 Jun 2017 22:08:20 +0200 Subject: [PATCH] save --- lib/ecoli_completed.c | 6 ++- lib/ecoli_node_cmd.c | 13 +++++++ lib/ecoli_node_expr.c | 15 +++++--- lib/ecoli_node_expr_test.c | 1 + lib/ecoli_node_seq.c | 75 ++++++++++++++++++++++++++++---------- lib/ecoli_node_subset.c | 4 +- lib/ecoli_parsed.c | 3 +- lib/main-readline.c | 28 +++++++++----- lib/todo.txt | 10 ++++- 9 files changed, 114 insertions(+), 41 deletions(-) diff --git a/lib/ecoli_completed.c b/lib/ecoli_completed.c index 60588e5..8ef14d5 100644 --- a/lib/ecoli_completed.c +++ b/lib/ecoli_completed.c @@ -118,6 +118,9 @@ struct ec_completed *ec_node_default_complete(const struct ec_node *gen_node, if (completed == NULL) return NULL; + if (ec_strvec_len(strvec) != 1) + return completed; + completed_elt = ec_completed_elt(gen_node, NULL); if (completed_elt == NULL) { ec_completed_free(completed); @@ -172,9 +175,8 @@ void ec_completed_add_elt( TAILQ_INSERT_TAIL(&completed->elts, elt, next); completed->count++; - if (elt->add != NULL) - completed->count_match++; if (elt->add != NULL) { + completed->count_match++; if (completed->smallest_start == NULL) { completed->smallest_start = ec_strdup(elt->add); } else { diff --git a/lib/ecoli_node_cmd.c b/lib/ecoli_node_cmd.c index 2753339..9a6c4eb 100644 --- a/lib/ecoli_node_cmd.c +++ b/lib/ecoli_node_cmd.c @@ -274,6 +274,8 @@ static int ec_node_cmd_build(struct ec_node *gen_node) void *result; int ret; + /* XXX the expr parser can be moved in the node init */ + /* build the expression parser */ ret = -ENOMEM; expr = ec_node("expr", "expr"); @@ -355,6 +357,7 @@ static int ec_node_cmd_build(struct ec_node *gen_node) goto fail; } ec_parsed_free(p); + p = NULL; ec_node_dump(stdout, cmd); ec_node_free(node->expr); @@ -367,6 +370,7 @@ static int ec_node_cmd_build(struct ec_node *gen_node) return 0; fail: + ec_parsed_free(p); ec_node_free(expr); ec_node_free(lex); ec_node_free(cmd); @@ -496,6 +500,15 @@ static int ec_node_cmd_testcase(void) ret |= EC_TEST_CHECK_PARSE(node, -1, "foo"); ec_node_free(node); + node = EC_NODE_CMD(NULL, "good morning bob|bobby|michael [count]", + ec_node_int("count", 0, 10, 10)); + if (node == NULL) { + ec_log(EC_LOG_ERR, "cannot create node\n"); + return -1; + } + ret |= EC_TEST_CHECK_PARSE(node, 4, "good", "morning", "bob", "1"); + ec_node_free(node); + // XXX completion return ret; diff --git a/lib/ecoli_node_expr.c b/lib/ecoli_node_expr.c index 672b62e..c158834 100644 --- a/lib/ecoli_node_expr.c +++ b/lib/ecoli_node_expr.c @@ -465,12 +465,15 @@ static int merge_results(void *userctx, return 0; } - if (x->has_val && x->op == NULL && y->has_val && y->op != NULL) { - ret = ops->eval_bin_op(&x->val, userctx, x->val, y->op, y->val); - if (ret < 0) - return ret; + if (x->has_val && y->has_val && y->op != NULL) { + if (y->op_type == BIN_OP) { + ret = ops->eval_bin_op(&x->val, userctx, x->val, + y->op, y->val); + if (ret < 0) + return ret; - return 0; + return 0; + } } if (x->has_val == 0 && x->op != NULL && y->has_val && y->op == NULL) { @@ -497,7 +500,7 @@ static int merge_results(void *userctx, return 0; } - assert(true); /* we should not get here */ + assert(false); /* we should not get here */ return -EINVAL; } diff --git a/lib/ecoli_node_expr_test.c b/lib/ecoli_node_expr_test.c index ea8938b..1e78212 100644 --- a/lib/ecoli_node_expr_test.c +++ b/lib/ecoli_node_expr_test.c @@ -282,6 +282,7 @@ static int ec_node_expr_testcase(void) ret |= ec_node_expr_test_eval(lex_node, node, "!0", 1); ret |= ec_node_expr_test_eval(lex_node, node, "1+1", 2); + ret |= ec_node_expr_test_eval(lex_node, node, "1+2+3", 6); ret |= ec_node_expr_test_eval(lex_node, node, "1+1*2", 4); ret |= ec_node_expr_test_eval(lex_node, node, "2 * 2^", 8); ret |= ec_node_expr_test_eval(lex_node, node, "(1 + !0)^ * !0^", 4); diff --git a/lib/ecoli_node_seq.c b/lib/ecoli_node_seq.c index cd103db..76258d3 100644 --- a/lib/ecoli_node_seq.c +++ b/lib/ecoli_node_seq.c @@ -101,60 +101,97 @@ fail: return NULL; } -static struct ec_completed *ec_node_seq_complete(const struct ec_node *gen_node, +static struct ec_completed * +__ec_node_seq_complete(struct ec_node **table, size_t table_len, const struct ec_strvec *strvec) { - struct ec_node_seq *node = (struct ec_node_seq *)gen_node; struct ec_completed *completed, *child_completed; struct ec_strvec *childvec = NULL; struct ec_parsed *parsed; - size_t len = 0; unsigned int i; completed = ec_completed(); if (completed == NULL) return NULL; - if (node->len == 0) + if (table_len == 0) return completed; - for (i = 0; i < node->len && len < ec_strvec_len(strvec); i++) { - childvec = ec_strvec_ndup(strvec, len, - ec_strvec_len(strvec) - len); - if (childvec == NULL) - goto fail; + /* + * Example of completion for a sequence node = [n1,n2] and an + * input = [a,b,c,d]: + * + * result = complete(n1, [a,b,c,d]) + + * complete(n2, [b,c,d]) if n1 matches [a] + + * complete(n2, [c,d]) if n1 matches [a,b] + + * complete(n2, [d]) if n1 matches [a,b,c] + + * complete(n2, []) if n1 matches [a,b,c,d] + */ + + /* first, try to complete with the first node of the table */ + child_completed = ec_node_complete_strvec(table[0], strvec); + if (child_completed == NULL) + goto fail; + ec_completed_merge(completed, child_completed); + child_completed = NULL; - child_completed = ec_node_complete_strvec(node->table[i], - childvec); - if (child_completed == NULL) + /* then, if the node matches the beginning of the strvec, try to + * complete the rest */ + for (i = 0; i < ec_strvec_len(strvec); i++) { + childvec = ec_strvec_ndup(strvec, 0, i); + if (childvec == NULL) goto fail; - ec_completed_merge(completed, child_completed); - - parsed = ec_node_parse_strvec(node->table[i], childvec); + parsed = ec_node_parse_strvec(table[0], childvec); if (parsed == NULL) goto fail; ec_strvec_free(childvec); childvec = NULL; - if (!ec_parsed_matches(parsed)) { + if (!ec_parsed_matches(parsed) || ec_parsed_len(parsed) != i) { ec_parsed_free(parsed); - break; + parsed = NULL; + continue; } - - len += ec_strvec_len(parsed->strvec); ec_parsed_free(parsed); + parsed = NULL; + + childvec = ec_strvec_ndup(strvec, i, ec_strvec_len(strvec) - i); + if (childvec == NULL) + goto fail; + + child_completed = __ec_node_seq_complete(&table[1], + table_len - 1, + childvec); + ec_strvec_free(childvec); + childvec = NULL; + + if (child_completed == NULL) + goto fail; + + ec_completed_merge(completed, child_completed); + child_completed = NULL; } return completed; fail: ec_strvec_free(childvec); + ec_parsed_free(parsed); + ec_completed_free(child_completed); ec_completed_free(completed); return NULL; } +static struct ec_completed *ec_node_seq_complete(const struct ec_node *gen_node, + const struct ec_strvec *strvec) +{ + struct ec_node_seq *node = (struct ec_node_seq *)gen_node; + + return __ec_node_seq_complete(node->table, node->len, strvec); +} + static void ec_node_seq_free_priv(struct ec_node *gen_node) { struct ec_node_seq *node = (struct ec_node_seq *)gen_node; diff --git a/lib/ecoli_node_subset.c b/lib/ecoli_node_subset.c index 2150656..48319e6 100644 --- a/lib/ecoli_node_subset.c +++ b/lib/ecoli_node_subset.c @@ -52,8 +52,8 @@ struct ec_node_subset { struct parse_result { struct ec_parsed **parsed_table; /* list of parsed node */ - size_t parsed_table_len; /* number of parsed node */ - size_t len; /* consumed strings */ + size_t parsed_table_len; /* number of parsed node */ + size_t len; /* consumed strings */ }; static int __ec_node_subset_parse(struct ec_node **table, size_t table_len, diff --git a/lib/ecoli_parsed.c b/lib/ecoli_parsed.c index b26b123..93d5325 100644 --- a/lib/ecoli_parsed.c +++ b/lib/ecoli_parsed.c @@ -223,8 +223,7 @@ struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed, return NULL; } -const struct ec_strvec *ec_parsed_strvec( - const struct ec_parsed *parsed) +const struct ec_strvec *ec_parsed_strvec(const struct ec_parsed *parsed) { if (parsed == NULL || parsed->strvec == NULL) return NULL; diff --git a/lib/main-readline.c b/lib/main-readline.c index 73df238..cde202a 100644 --- a/lib/main-readline.c +++ b/lib/main-readline.c @@ -124,9 +124,11 @@ static int show_help(int ignore, int invoking_key) const struct ec_completed_elt *elt; struct ec_completed_iter *iter; struct ec_completed *c; + struct ec_parsed *p; char *line; unsigned int count, i; char **helps = NULL; + int match = 0; (void)ignore; (void)invoking_key; @@ -134,33 +136,43 @@ static int show_help(int ignore, int invoking_key) line = strdup(rl_line_buffer); if (line == NULL) return 1; - line[rl_point] = '\0'; + /* check if the current line matches */ + p = ec_node_parse(commands, line); + if (ec_parsed_matches(p)) + match = 1; + ec_parsed_free(p); + + /* complete at current cursor position */ + line[rl_point] = '\0'; c = ec_node_complete(commands, line); + ec_completed_dump(stdout, c); free(line); if (c == NULL) return 1; - //ec_completed_dump(stdout, c); count = ec_completed_count(c, EC_MATCH | EC_NO_MATCH); - helps = calloc(count + 1, sizeof(char *)); + helps = calloc(count + match + 1, sizeof(char *)); if (helps == NULL) return 1; + if (match) + helps[1] = ""; + iter = ec_completed_iter(c, EC_MATCH | EC_NO_MATCH); if (iter == NULL) goto fail; /* strangely, rl_display_match_list() expects first index at 1 */ - for (i = 1, elt = ec_completed_iter_next(iter); - i <= count && elt != NULL; + for (i = match + 1, elt = ec_completed_iter_next(iter); + i < count + match + 1 && elt != NULL; i++, elt = ec_completed_iter_next(iter)) { helps[i] = get_tk_help(elt->node); } ec_completed_free(c); - rl_display_match_list(helps, count, 1000); + rl_display_match_list(helps, count + match, 1000); /* XXX 1000 */ rl_forced_update_display(); @@ -200,8 +212,7 @@ static int create_commands(void) if (ec_node_or_add(cmdlist, cmd) < 0) goto fail; -#if 0 - cmd = EC_NODE_CMD(NULL, "good morning john|johnny|mike [count]", + cmd = EC_NODE_CMD(NULL, "good morning bob|bobby|michael [count]", ec_node_int("count", 0, 10, 10)); if (cmd == NULL) goto fail; @@ -209,7 +220,6 @@ static int create_commands(void) "say good morning to someone several times", NULL); if (ec_node_or_add(cmdlist, cmd) < 0) goto fail; -#endif cmd = EC_NODE_SEQ(NULL, ec_node_str(NULL, "bye") diff --git a/lib/todo.txt b/lib/todo.txt index a29054c..0633d0f 100644 --- a/lib/todo.txt +++ b/lib/todo.txt @@ -21,7 +21,7 @@ X remove the _new() functions - missing static / const - license: "s/neither the name...may/the names of its contributors may not/" - check all completion nodes -- split ecoli_tk.h +X split ecoli_tk.h - cache results when appropriate? - size_t or unsigned int? X rename: @@ -35,6 +35,7 @@ dependencies ============ - pass the current parsed state when parsing/completing +- new node "condition" logs ==== @@ -47,6 +48,12 @@ yaml X register nodes by name - interface to add attributes: all nodes must be configurable through a generic api + - attr string + - attr string list + - attr node + - attr node list + - attr int + - yaml interface to create nodes - example @@ -71,6 +78,7 @@ doc - each node - allocation model - say that it stops at first match (no ambigous support) +- say that completion must be exhaustive build framework =============== -- 2.39.5