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);
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 {
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");
goto fail;
}
ec_parsed_free(p);
+ p = NULL;
ec_node_dump(stdout, cmd);
ec_node_free(node->expr);
return 0;
fail:
+ ec_parsed_free(p);
ec_node_free(expr);
ec_node_free(lex);
ec_node_free(cmd);
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;
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) {
return 0;
}
- assert(true); /* we should not get here */
+ assert(false); /* we should not get here */
return -EINVAL;
}
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);
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;
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,
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;
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;
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();
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;
"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")
- 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:
============
- pass the current parsed state when parsing/completing
+- new node "condition"
logs
====
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
- each node
- allocation model
- say that it stops at first match (no ambigous support)
+- say that completion must be exhaustive
build framework
===============