save
authorOlivier Matz <zer0@droids-corp.org>
Thu, 29 Jun 2017 20:08:20 +0000 (22:08 +0200)
committerOlivier Matz <zer0@droids-corp.org>
Thu, 29 Jun 2017 20:08:20 +0000 (22:08 +0200)
lib/ecoli_completed.c
lib/ecoli_node_cmd.c
lib/ecoli_node_expr.c
lib/ecoli_node_expr_test.c
lib/ecoli_node_seq.c
lib/ecoli_node_subset.c
lib/ecoli_parsed.c
lib/main-readline.c
lib/todo.txt

index 60588e5..8ef14d5 100644 (file)
@@ -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 {
index 2753339..9a6c4eb 100644 (file)
@@ -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;
index 672b62e..c158834 100644 (file)
@@ -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;
 }
 
index ea8938b..1e78212 100644 (file)
@@ -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);
index cd103db..76258d3 100644 (file)
@@ -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;
index 2150656..48319e6 100644 (file)
@@ -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,
index b26b123..93d5325 100644 (file)
@@ -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;
index 73df238..cde202a 100644 (file)
@@ -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] = "<return>";
+
        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")
index a29054c..0633d0f 100644 (file)
@@ -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
 ===============