store full token and completion in completed_item
authorOlivier Matz <zer0@droids-corp.org>
Thu, 1 Feb 2018 21:32:43 +0000 (22:32 +0100)
committerOlivier Matz <zer0@droids-corp.org>
Thu, 1 Feb 2018 21:32:43 +0000 (22:32 +0100)
16 files changed:
lib/ecoli_completed.c
lib/ecoli_completed.h
lib/ecoli_node.c
lib/ecoli_node.h
lib/ecoli_node_expr.c
lib/ecoli_node_file.c
lib/ecoli_node_int.c
lib/ecoli_node_many.c
lib/ecoli_node_once.c
lib/ecoli_node_seq.c
lib/ecoli_node_sh_lex.c
lib/ecoli_node_str.c
lib/ecoli_node_subset.c
lib/ecoli_parsed.c
lib/main-readline.c
lib/todo.txt

index 6820971..25ae6cb 100644 (file)
@@ -32,6 +32,7 @@
 #include <errno.h>
 
 #include <ecoli_malloc.h>
+#include <ecoli_string.h>
 #include <ecoli_strvec.h>
 #include <ecoli_keyval.h>
 #include <ecoli_log.h>
@@ -44,12 +45,14 @@ struct ec_completed_item {
        enum ec_completed_type type;
        const struct ec_node *node;
        struct ec_completed_group *grp;
-       char *str;
-       char *display;
+       char *start;      /* the initial token */
+       char *full;       /* the full token after completion */
+       char *completion; /* chars that are added, NULL if not applicable */
+       char *display;    /* what should be displayed by help/completers */
        struct ec_keyval *attrs;
 };
 
-struct ec_completed *ec_completed(void)
+struct ec_completed *ec_completed(struct ec_parsed *state)
 {
        struct ec_completed *completed = NULL;
 
@@ -59,23 +62,17 @@ struct ec_completed *ec_completed(void)
 
        TAILQ_INIT(&completed->groups);
 
-       completed->attrs = ec_keyval();
-       if (completed->attrs == NULL)
-               goto fail;
-
-       completed->cur_state = NULL;
+       completed->cur_state = state;
 
        return completed;
 
  fail:
-       if (completed != NULL)
-               ec_keyval_free(completed->attrs);
        ec_free(completed);
 
        return NULL;
 }
 
-struct ec_parsed *ec_completed_cur_parse_state(struct ec_completed *completed)
+struct ec_parsed *ec_completed_get_state(struct ec_completed *completed)
 {
        return completed->cur_state;
 }
@@ -114,7 +111,7 @@ ec_node_complete_child(struct ec_node *node, struct ec_completed *completed,
        cur_group = completed->cur_group;
        completed->cur_group = NULL;
 
-       /* complete */
+       /* fill the completed struct with items */
        ret = node->type->complete(node, completed, strvec);
 
        /* restore parent parse state */
@@ -145,7 +142,7 @@ struct ec_completed *ec_node_complete_strvec(struct ec_node *node,
        struct ec_completed *completed = NULL;
        int ret;
 
-       completed = ec_completed();
+       completed = ec_completed(NULL);
        if (completed == NULL)
                goto fail;
 
@@ -195,6 +192,10 @@ ec_completed_group(const struct ec_node *node, struct ec_parsed *parsed)
        if (grp == NULL)
                return NULL;
 
+       grp->attrs = ec_keyval();
+       if (grp->attrs == NULL)
+               goto fail;
+
        grp->state = ec_parsed_dup(parsed);
        if (grp->state == NULL)
                goto fail;
@@ -205,116 +206,158 @@ ec_completed_group(const struct ec_node *node, struct ec_parsed *parsed)
        return grp;
 
 fail:
-       if (grp != NULL)
+       if (grp != NULL) {
                ec_parsed_free(grp->state);
+               ec_keyval_free(grp->attrs);
+       }
        ec_free(grp);
        return NULL;
 }
 
-struct ec_completed_item *
-ec_completed_item(const struct ec_node *node)
+static struct ec_completed_item *
+ec_completed_item(const struct ec_node *node, enum ec_completed_type type,
+               const char *start, const char *full)
 {
        struct ec_completed_item *item = NULL;
+       struct ec_keyval *attrs = NULL;
+       char *comp_cp = NULL, *start_cp = NULL;
+       char *full_cp = NULL, *display_cp = NULL;
+
+       if (type == EC_COMP_UNKNOWN && full != NULL) {
+               errno = EINVAL;
+               return NULL;
+       }
+       if (type != EC_COMP_UNKNOWN && full == NULL) {
+               errno = EINVAL;
+               return NULL;
+       }
 
        item = ec_calloc(1, sizeof(*item));
        if (item == NULL)
                goto fail;
 
-       item->attrs = ec_keyval();
-       if (item->attrs == NULL)
+       attrs = ec_keyval();
+       if (attrs == NULL)
                goto fail;
 
-       item->type = EC_COMP_UNKNOWN;
+       if (start != NULL) {
+               start_cp = ec_strdup(start);
+               if (start_cp == NULL)
+                       goto fail;
+
+               if (ec_str_startswith(full, start)) {
+                       comp_cp = ec_strdup(&full[strlen(start)]);
+                       if (comp_cp == NULL)
+                               goto fail;
+               }
+       }
+       if (full != NULL) {
+               full_cp = ec_strdup(full);
+               if (full_cp == NULL)
+                       goto fail;
+               display_cp = ec_strdup(full);
+               if (display_cp == NULL)
+                       goto fail;
+       }
+
        item->node = node;
+       item->type = type;
+       item->start = start_cp;
+       item->full = full_cp;
+       item->completion = comp_cp;
+       item->display = display_cp;
+       item->attrs = attrs;
 
        return item;
 
 fail:
-       if (item != NULL) {
-               ec_free(item->str);
-               ec_free(item->display);
-               ec_keyval_free(item->attrs);
-       }
+       ec_keyval_free(item->attrs);
+       ec_free(comp_cp);
+       ec_free(start_cp);
+       ec_free(full_cp);
+       ec_free(display_cp);
        ec_free(item);
 
        return NULL;
 }
 
-int
-ec_completed_item_set(struct ec_completed_item *item,
-               enum ec_completed_type type, const char *str)
+int ec_completed_item_set_display(struct ec_completed_item *item,
+                               const char *display)
 {
-       char *str_copy = NULL;
        char *display_copy = NULL;
        int ret = 0;
 
-       if (item == NULL)
-               return -EINVAL;
-       if (item->str != NULL)
-               return -EEXIST;
-
-       switch (type) {
-       case EC_COMP_UNKNOWN:
-               if (str != NULL)
-                       return -EINVAL;
-               break;
-       case EC_COMP_FULL:
-       case EC_PARTIAL_MATCH:
-               if (str == NULL)
-                       return -EINVAL;
-               break;
-       default:
+       if (item == NULL || display == NULL ||
+                       item->type == EC_COMP_UNKNOWN)
                return -EINVAL;
-       }
 
-       if (str != NULL) {
-               ret = -ENOMEM;
-               str_copy = ec_strdup(str);
-               if (str_copy == NULL)
-                       goto fail;
-               display_copy = ec_strdup(str);
-               if (display_copy == NULL)
-                       goto fail;
-       }
+       display_copy = ec_strdup(display);
+       if (display_copy == NULL)
+               goto fail;
 
-       item->type = type;
-       item->str = str_copy;
+       ec_free(item->display);
        item->display = display_copy;
+
        return 0;
 
 fail:
-       ec_free(str_copy);
        ec_free(display_copy);
        return ret;
 }
 
-int ec_completed_item_set_display(struct ec_completed_item *item,
-                               const char *display)
+int
+ec_completed_item_set_completion(struct ec_completed_item *item,
+                               const char *completion)
 {
-       char *display_copy = NULL;
+       char *completion_copy = NULL;
        int ret = 0;
 
-       if (item == NULL || display == NULL ||
-                       item->type == EC_COMP_UNKNOWN || item->str == NULL)
+       if (item == NULL || completion == NULL ||
+                       item->type == EC_COMP_UNKNOWN)
                return -EINVAL;
 
        ret = -ENOMEM;
-       display_copy = ec_strdup(display);
-       if (display_copy == NULL)
+       completion_copy = ec_strdup(completion);
+       if (completion_copy == NULL)
                goto fail;
 
-       ec_free(item->display);
-       item->display = display_copy;
+       ec_free(item->completion);
+       item->completion = completion_copy;
 
        return 0;
 
 fail:
-       ec_free(display_copy);
+       ec_free(completion_copy);
        return ret;
 }
 
-// XXX refactor ec_completed_item(), ec_completed_item_add(), ec_completed_item_set* 
 int
+ec_completed_item_set_str(struct ec_completed_item *item,
+                       const char *str)
+{
+       char *str_copy = NULL;
+       int ret = 0;
+
+       if (item == NULL || str == NULL ||
+                       item->type == EC_COMP_UNKNOWN)
+               return -EINVAL;
+
+       ret = -ENOMEM;
+       str_copy = ec_strdup(str);
+       if (str_copy == NULL)
+               goto fail;
+
+       ec_free(item->full);
+       item->full = str_copy;
+
+       return 0;
+
+fail:
+       ec_free(str_copy);
+       return ret;
+}
+
+static int
 ec_completed_item_add(struct ec_completed *completed,
                struct ec_completed_item *item)
 {
@@ -325,7 +368,7 @@ ec_completed_item_add(struct ec_completed *completed,
        case EC_COMP_UNKNOWN:
                break;
        case EC_COMP_FULL:
-       case EC_PARTIAL_MATCH:
+       case EC_COMP_PARTIAL:
                completed->count_match++; //XXX
                break;
        default:
@@ -352,7 +395,7 @@ ec_completed_item_add(struct ec_completed *completed,
 const char *
 ec_completed_item_get_str(const struct ec_completed_item *item)
 {
-       return item->str;
+       return item->full;
 }
 
 const char *
@@ -361,6 +404,12 @@ ec_completed_item_get_display(const struct ec_completed_item *item)
        return item->display;
 }
 
+const char *
+ec_completed_item_get_completion(const struct ec_completed_item *item)
+{
+       return item->completion;
+}
+
 enum ec_completed_type
 ec_completed_item_get_type(const struct ec_completed_item *item)
 {
@@ -379,42 +428,63 @@ ec_completed_item_get_grp(const struct ec_completed_item *item)
        return item->grp;
 }
 
-void ec_completed_item_free(struct ec_completed_item *item)
+static void
+ec_completed_item_free(struct ec_completed_item *item)
 {
        if (item == NULL)
                return;
 
-       ec_free(item->str);
+       ec_free(item->full);
+       ec_free(item->start);
+       ec_free(item->completion);
        ec_free(item->display);
        ec_keyval_free(item->attrs);
        ec_free(item);
 }
 
+int ec_completed_add_item(struct ec_completed *completed,
+                       const struct ec_node *node,
+                       struct ec_completed_item **p_item,
+                       enum ec_completed_type type,
+                       const char *start, const char *full)
+{
+       struct ec_completed_item *item = NULL;
+       int ret;
+
+       item = ec_completed_item(node, type, start, full);
+       if (item == NULL)
+               return -1;
+
+       ret = ec_completed_item_add(completed, item);
+       if (ret < 0)
+               goto fail;
+
+       if (p_item != NULL)
+               *p_item = item;
+
+       return 0;
+
+fail:
+       ec_completed_item_free(item);
+
+       return -1;
+}
+
 /* default completion function: return a no-match element */
 int
 ec_node_default_complete(const struct ec_node *gen_node, // XXX rename in nomatch
                        struct ec_completed *completed,
                        const struct ec_strvec *strvec)
 {
-       struct ec_completed_item *item = NULL;
        int ret;
 
        if (ec_strvec_len(strvec) != 1)
                return 0;
 
-       item = ec_completed_item(gen_node);
-       if (item == NULL)
-               return -ENOMEM;
-       ret = ec_completed_item_set(item, EC_COMP_UNKNOWN, NULL);
-       if (ret < 0) {
-               ec_completed_item_free(item);
-               return ret;
-       }
-       ret = ec_completed_item_add(completed, item);
-       if (ret < 0) {
-               ec_completed_item_free(item);
+       ret = ec_completed_add_item(completed, gen_node, NULL,
+                               EC_COMP_UNKNOWN, NULL, NULL);
+       if (ret < 0)
                return ret;
-       }
 
        return 0;
 }
@@ -432,6 +502,7 @@ static void ec_completed_group_free(struct ec_completed_group *grp)
                ec_completed_item_free(item);
        }
        ec_parsed_free(ec_parsed_get_root(grp->state));
+       ec_keyval_free(grp->attrs);
        ec_free(grp);
 }
 
@@ -447,7 +518,6 @@ void ec_completed_free(struct ec_completed *completed)
                TAILQ_REMOVE(&completed->groups, grp, next);
                ec_completed_group_free(grp);
        }
-       ec_keyval_free(completed->attrs);
        ec_free(completed);
 }
 
@@ -471,18 +541,36 @@ void ec_completed_dump(FILE *out, const struct ec_completed *completed)
                        const char *typestr;
 
                        switch (item->type) {
-                       case EC_COMP_UNKNOWN: typestr = "no-match"; break;
-                       case EC_COMP_FULL: typestr = "match"; break;
-                       case EC_PARTIAL_MATCH: typestr = "partial-match"; break;
+                       case EC_COMP_UNKNOWN: typestr = "unknown"; break;
+                       case EC_COMP_FULL: typestr = "full"; break;
+                       case EC_COMP_PARTIAL: typestr = "partial"; break;
                        default: typestr = "unknown"; break;
                        }
 
-                       fprintf(out, "  type=%s str=<%s> disp=<%s>\n",
-                               typestr, item->str, item->display);
+                       fprintf(out, "  type=%s str=<%s> comp=<%s> disp=<%s>\n",
+                               typestr, item->full, item->completion,
+                               item->display);
                }
        }
 }
 
+int ec_completed_merge(struct ec_completed *to,
+               struct ec_completed *from)
+{
+       struct ec_completed_group *grp;
+
+       while (!TAILQ_EMPTY(&from->groups)) {
+               grp = TAILQ_FIRST(&from->groups);
+               TAILQ_REMOVE(&from->groups, grp, next);
+               TAILQ_INSERT_TAIL(&to->groups, grp, next);
+       }
+       to->count += from->count;
+       to->count_match += from->count_match;
+
+       ec_completed_free(from);
+       return 0;
+}
+
 unsigned int ec_completed_count(
        const struct ec_completed *completed,
        enum ec_completed_type type)
@@ -518,12 +606,12 @@ ec_completed_iter(struct ec_completed *completed,
        return iter;
 }
 
-const struct ec_completed_item *ec_completed_iter_next(
+struct ec_completed_item *ec_completed_iter_next(
        struct ec_completed_iter *iter)
 {
-       const struct ec_completed *completed = iter->completed;
-       const struct ec_completed_group *cur_node;
-       const struct ec_completed_item *cur_match;
+       struct ec_completed *completed = iter->completed;
+       struct ec_completed_group *cur_node;
+       struct ec_completed_item *cur_match;
 
        if (completed == NULL)
                return NULL;
index c054994..f616e4b 100644 (file)
 struct ec_node;
 
 enum ec_completed_type {
-       EC_COMP_UNKNOWN,
-       EC_COMP_FULL,
-       EC_PARTIAL_MATCH,
+       EC_COMP_UNKNOWN = 0x1,
+       EC_COMP_FULL = 0x2,
+       EC_COMP_PARTIAL = 0x4,
+       EC_COMP_ALL = 0x7,
 };
 
 struct ec_completed_item;
@@ -58,6 +59,7 @@ struct ec_completed_group {
        const struct ec_node *node;
        struct ec_completed_item_list items;
        struct ec_parsed *state;
+       struct ec_keyval *attrs;
 };
 
 TAILQ_HEAD(ec_completed_group_list, ec_completed_group);
@@ -68,7 +70,6 @@ struct ec_completed {
        struct ec_parsed *cur_state;
        struct ec_completed_group *cur_group;
        struct ec_completed_group_list groups;
-       struct ec_keyval *attrs; // XXX per node instead?
 };
 
 /*
@@ -90,7 +91,7 @@ int ec_node_complete_child(struct ec_node *node,
  *
  *
  */
-struct ec_completed *ec_completed(void);
+struct ec_completed *ec_completed(struct ec_parsed *state);
 
 /**
  * Free a completion object and all its items.
@@ -107,32 +108,28 @@ void ec_completed_free(struct ec_completed *completed);
 void ec_completed_dump(FILE *out,
        const struct ec_completed *completed);
 
-
-struct ec_parsed *ec_completed_cur_parse_state(struct ec_completed *completed);
-
 /**
- * Create a completion item.
- *
+ * Merge items contained in 'from' into 'to'
  *
+ * The 'from' completed struct is freed.
  */
-struct ec_completed_item *
-ec_completed_item(const struct ec_node *node);
+int ec_completed_merge(struct ec_completed *to,
+               struct ec_completed *from);
 
-/**
- * Set type and value of a completion item.
- *
- *
- */
-int ec_completed_item_set(struct ec_completed_item *item,
-                       enum ec_completed_type type, const char *str);
+struct ec_parsed *ec_completed_get_state(struct ec_completed *completed);
+
+/* shortcut for ec_completed_item() + ec_completed_item_add() */
+int ec_completed_add_item(struct ec_completed *completed,
+                       const struct ec_node *node,
+                       struct ec_completed_item **p_item,
+                       enum ec_completed_type type,
+                       const char *start, const char *full);
 
 /**
- * Add a completion item to a completion list.
- *
  *
  */
-int ec_completed_item_add(struct ec_completed *completed,
-                       struct ec_completed_item *item);
+int ec_completed_item_set_str(struct ec_completed_item *item,
+                       const char *str);
 
 /**
  * Get the string value of a completion item.
@@ -150,6 +147,14 @@ ec_completed_item_get_str(const struct ec_completed_item *item);
 const char *
 ec_completed_item_get_display(const struct ec_completed_item *item);
 
+/**
+ * Get the completion string value of a completion item.
+ *
+ *
+ */
+const char *
+ec_completed_item_get_completion(const struct ec_completed_item *item);
+
 /**
  * Get the group of a completion item.
  *
@@ -175,19 +180,20 @@ const struct ec_node *
 ec_completed_item_get_node(const struct ec_completed_item *item);
 
 /**
- *
+ * Set the display value of an item.
  *
  *
  */
-void ec_completed_item_free(struct ec_completed_item *item);
+int ec_completed_item_set_display(struct ec_completed_item *item,
+                               const char *display);
 
 /**
- * Set the display value of an item.
+ * Set the completion value of an item.
  *
  *
  */
-int ec_completed_item_set_display(struct ec_completed_item *item,
-                               const char *display);
+int ec_completed_item_set_completion(struct ec_completed_item *item,
+                               const char *completion);
 
 /**
  *
@@ -215,9 +221,9 @@ unsigned int ec_completed_count(
  */
 struct ec_completed_iter {
        enum ec_completed_type type;
-       const struct ec_completed *completed;
-       const struct ec_completed_group *cur_node;
-       const struct ec_completed_item *cur_match;
+       struct ec_completed *completed;
+       struct ec_completed_group *cur_node;
+       struct ec_completed_item *cur_match;
 };
 
 /**
@@ -234,7 +240,7 @@ ec_completed_iter(struct ec_completed *completed,
  *
  *
  */
-const struct ec_completed_item *ec_completed_iter_next(
+struct ec_completed_item *ec_completed_iter_next(
        struct ec_completed_iter *iter);
 
 /**
index 6cd95d7..089c0bc 100644 (file)
@@ -243,3 +243,11 @@ const char *ec_node_desc(const struct ec_node *node)
 
        return node->desc;
 }
+
+int ec_node_check_type(const struct ec_node *node,
+               const struct ec_node_type *type)
+{
+       if (strcmp(node->type->name, type->name))
+               return -EINVAL;
+       return 0;
+}
index 8fe2d76..8afcdbc 100644 (file)
@@ -187,4 +187,8 @@ const char *ec_node_desc(const struct ec_node *node);
 void ec_node_dump(FILE *out, const struct ec_node *node);
 struct ec_node *ec_node_find(struct ec_node *node, const char *id);
 
+/* check the type of a node */
+int ec_node_check_type(const struct ec_node *node,
+               const struct ec_node_type *type);
+
 #endif
index 129163e..4c546a7 100644 (file)
@@ -243,6 +243,10 @@ int ec_node_expr_set_val_node(struct ec_node *gen_node, struct ec_node *val_node
        struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
        int ret;
 
+       ret = ec_node_check_type(gen_node, &ec_node_expr_type);
+       if (ret < 0)
+               return ret;
+
        ret = -EINVAL;
        if (val_node == NULL)
                goto fail;
@@ -270,7 +274,9 @@ int ec_node_expr_add_bin_op(struct ec_node *gen_node, struct ec_node *op)
        struct ec_node **bin_ops;
        int ret;
 
-       // XXX check node type
+       ret = ec_node_check_type(gen_node, &ec_node_expr_type);
+       if (ret < 0)
+               return ret;
 
        ret = -EINVAL;
        if (node == NULL || op == NULL)
@@ -304,7 +310,9 @@ int ec_node_expr_add_pre_op(struct ec_node *gen_node, struct ec_node *op)
        struct ec_node **pre_ops;
        int ret;
 
-       // XXX check node type
+       ret = ec_node_check_type(gen_node, &ec_node_expr_type);
+       if (ret < 0)
+               return ret;
 
        ret = -EINVAL;
        if (node == NULL || op == NULL)
@@ -338,7 +346,9 @@ int ec_node_expr_add_post_op(struct ec_node *gen_node, struct ec_node *op)
        struct ec_node **post_ops;
        int ret;
 
-       // XXX check node type
+       ret = ec_node_check_type(gen_node, &ec_node_expr_type);
+       if (ret < 0)
+               return ret;
 
        ret = -EINVAL;
        if (node == NULL || op == NULL)
@@ -373,7 +383,9 @@ int ec_node_expr_add_parenthesis(struct ec_node *gen_node,
        struct ec_node **open_ops, **close_ops;
        int ret;
 
-       // XXX check node type
+       ret = ec_node_check_type(gen_node, &ec_node_expr_type);
+       if (ret < 0)
+               return ret;
 
        ret = -EINVAL;
        if (node == NULL || open == NULL || close == NULL)
@@ -416,6 +428,7 @@ enum expr_node_type {
        PAREN_OPEN,
        PAREN_CLOSE,
 };
+
 static enum expr_node_type get_node_type(const struct ec_node *expr_gen_node,
        const struct ec_node *check)
 {
index 951c494..8bb7edd 100644 (file)
@@ -118,13 +118,14 @@ ec_node_file_complete(const struct ec_node *gen_node,
                struct ec_completed *completed,
                const struct ec_strvec *strvec)
 {
+       char *dname = NULL, *bname = NULL, *effective_dir;
        struct ec_completed_item *item = NULL;
+       enum ec_completed_type type;
        struct stat st;
        const char *input;
        size_t bname_len;
        struct dirent *de = NULL;
        DIR *dir = NULL;
-       char *dname = NULL, *bname = NULL, *effective_dir;
        char *comp_str = NULL;
        char *disp_str = NULL;
        int ret;
@@ -199,13 +200,8 @@ ec_node_file_complete(const struct ec_node *gen_node,
                        is_dir = 0;
                }
 
-               item = ec_completed_item(gen_node);
-               if (item == NULL) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-
                if (is_dir) {
+                       type = EC_COMP_PARTIAL;
                        if (asprintf(&comp_str, "%s%s/", input,
                                        &de->d_name[bname_len]) < 0) {
                                ret = -errno;
@@ -215,11 +211,8 @@ ec_node_file_complete(const struct ec_node *gen_node,
                                ret = -errno;
                                goto out;
                        }
-                       ret = ec_completed_item_set(item, EC_PARTIAL_MATCH,
-                                               comp_str);
-                       if (ret < 0)
-                               goto out;
                } else {
+                       type = EC_COMP_FULL;
                        if (asprintf(&comp_str, "%s%s", input,
                                        &de->d_name[bname_len]) < 0) {
                                ret = -errno;
@@ -229,15 +222,15 @@ ec_node_file_complete(const struct ec_node *gen_node,
                                ret = -errno;
                                goto out;
                        }
-                       ret = ec_completed_item_set(item, EC_COMP_FULL,
-                                               comp_str);
-                       if (ret < 0)
-                               goto out;
                }
-               ret = ec_completed_item_set_display(item, disp_str);
+               ret = ec_completed_add_item(completed, gen_node, &item,
+                                       type, input, comp_str);
                if (ret < 0)
                        goto out;
-               ret = ec_completed_item_add(completed, item);
+
+               /* fix the display string: we don't want to display the full
+                * path. */
+               ret = ec_completed_item_set_display(item, disp_str);
                if (ret < 0)
                        goto out;
 
@@ -250,7 +243,6 @@ ec_node_file_complete(const struct ec_node *gen_node,
        ret = 0;
 
 out:
-       ec_completed_item_free(item);
        free(comp_str);
        free(disp_str);
        ec_free(dname);
index cb7f60b..bd262fa 100644 (file)
@@ -209,6 +209,7 @@ int64_t ec_node_int_getval(struct ec_node *gen_node, const char *str)
 
        // XXX check type here
        // if gen_node->type != int fail
+       // we may need to change the API (return int + val in a ptr ?)
 
        parse_llint(node, str, &val);
 
index 8395bd1..c718890 100644 (file)
@@ -108,7 +108,7 @@ __ec_node_many_complete(struct ec_node_many *node, unsigned int max,
                        struct ec_completed *completed,
                        const struct ec_strvec *strvec)
 {
-       struct ec_parsed *parsed = ec_completed_cur_parse_state(completed);
+       struct ec_parsed *parsed = ec_completed_get_state(completed);
        struct ec_strvec *childvec = NULL;
        unsigned int i;
        int ret;
index 2020088..b01640d 100644 (file)
@@ -93,7 +93,7 @@ ec_node_once_complete(const struct ec_node *gen_node,
                const struct ec_strvec *strvec)
 {
        struct ec_node_once *node = (struct ec_node_once *)gen_node;
-       struct ec_parsed *parsed = ec_completed_cur_parse_state(completed);
+       struct ec_parsed *parsed = ec_completed_get_state(completed);
        unsigned int count;
        int ret;
 
@@ -131,14 +131,15 @@ EC_NODE_TYPE_REGISTER(ec_node_once_type);
 int ec_node_once_set(struct ec_node *gen_node, struct ec_node *child)
 {
        struct ec_node_once *node = (struct ec_node_once *)gen_node;
+       int ret;
 
-       // XXX check node type
-
-       assert(node != NULL);
-
-       if (child == NULL)
+       if (gen_node == NULL || child == NULL)
                return -EINVAL;
 
+       ret = ec_node_check_type(gen_node, &ec_node_once_type);
+       if (ret < 0)
+               return ret;
+
        gen_node->flags &= ~EC_NODE_F_BUILT;
 
        node->child = child;
index 6025fd7..9e0440b 100644 (file)
@@ -100,7 +100,7 @@ __ec_node_seq_complete(struct ec_node **table, size_t table_len,
                struct ec_completed *completed,
                const struct ec_strvec *strvec)
 {
-       struct ec_parsed *parsed = ec_completed_cur_parse_state(completed);
+       struct ec_parsed *parsed = ec_completed_get_state(completed);
        struct ec_strvec *childvec = NULL;
        unsigned int i;
        int ret;
index 1a5e4ab..e3580d7 100644 (file)
@@ -25,6 +25,7 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#define _GNU_SOURCE /* for asprintf */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -164,6 +165,8 @@ static struct ec_strvec *tokenize(const char *str, int completion,
                goto fail;
 
        while (str[off] != '\0') {
+               if (missing_quote != NULL)
+                       *missing_quote = '\0';
                len = eat_spaces(&str[off]);
                if (len > 0)
                        last_is_space = 1;
@@ -172,6 +175,8 @@ static struct ec_strvec *tokenize(const char *str, int completion,
                len = 0;
                suboff = off;
                while (str[suboff] != '\0') {
+                       if (missing_quote != NULL)
+                               *missing_quote = '\0';
                        last_is_space = 0;
                        if (str[suboff] == '"' || str[suboff] == '\'') {
                                sublen = eat_quoted_str(&str[suboff]);
@@ -211,8 +216,6 @@ static struct ec_strvec *tokenize(const char *str, int completion,
                        concat = NULL;
                }
 
-               /* XXX remove all printf comments */
-//             printf("str off=%zd len=%zd\n", off, len);
                off += len;
        }
 
@@ -283,7 +286,11 @@ ec_node_sh_lex_complete(const struct ec_node *gen_node,
                        const struct ec_strvec *strvec)
 {
        struct ec_node_sh_lex *node = (struct ec_node_sh_lex *)gen_node;
+       struct ec_completed *tmp_completed = NULL;
        struct ec_strvec *new_vec = NULL;
+       struct ec_completed_iter *iter = NULL;
+       struct ec_completed_item *item = NULL;
+       char *new_str = NULL;
        const char *str;
        char missing_quote;
        int ret;
@@ -292,24 +299,63 @@ ec_node_sh_lex_complete(const struct ec_node *gen_node,
                return 0;
 
        str = ec_strvec_val(strvec, 0);
-//     printf("\nold:%s\n", str);
        new_vec = tokenize(str, 1, 1, &missing_quote);
        if (new_vec == NULL)
                goto fail;
-//     printf("new:%s\n", ec_strvec_val(new_vec, 0));
 
-       // XXX: complete should add the quotes for !EC_PARTIAL
-       // XXX: if no quotes, replace " " by "\ "
-       ret = ec_node_complete_child(node->child, completed, new_vec);
+       /* we will store the completions in a temporary struct, because
+        * we want to update them (ex: add missing quotes) */
+       tmp_completed = ec_completed(ec_completed_get_state(completed));
+       if (tmp_completed == NULL)
+               goto fail;
+
+       ret = ec_node_complete_child(node->child, tmp_completed, new_vec);
        if (ret < 0)
                goto fail;
 
+       /* add missing quote for full completions  */
+       if (missing_quote != '\0') {
+               iter = ec_completed_iter(tmp_completed, EC_COMP_FULL);
+               if (iter == NULL)
+                       goto fail;
+               while ((item = ec_completed_iter_next(iter)) != NULL) {
+                       str = ec_completed_item_get_str(item);
+                       if (asprintf(&new_str, "%c%s%c", missing_quote, str,
+                                       missing_quote) < 0) {
+                               new_str = NULL;
+                               goto fail;
+                       }
+                       if (ec_completed_item_set_str(item, new_str) < 0)
+                               goto fail;
+                       free(new_str);
+                       new_str = NULL;
+
+                       str = ec_completed_item_get_completion(item);
+                       if (asprintf(&new_str, "%s%c", str,
+                                       missing_quote) < 0) {
+                               new_str = NULL;
+                               goto fail;
+                       }
+                       if (ec_completed_item_set_completion(item, new_str) < 0)
+                               goto fail;
+                       free(new_str);
+                       new_str = NULL;
+               }
+       }
+
+       ec_completed_iter_free(iter);
        ec_strvec_free(new_vec);
 
+       ec_completed_merge(completed, tmp_completed);
+
        return 0;
 
  fail:
+       ec_completed_free(tmp_completed);
+       ec_completed_iter_free(iter);
        ec_strvec_free(new_vec);
+       free(new_str);
+
        return -1;
 }
 
@@ -425,6 +471,9 @@ static int ec_node_sh_lex_testcase(void)
        ret |= EC_TEST_CHECK_COMPLETE(node,
                "foo barx", EC_NODE_ENDLIST,
                EC_NODE_ENDLIST);
+       ret |= EC_TEST_CHECK_COMPLETE(node,
+               "foo 'b", EC_NODE_ENDLIST,
+               "'bar'", EC_NODE_ENDLIST);
 
        ec_node_free(node);
        return ret;
index 6c47980..ab7ff11 100644 (file)
@@ -72,11 +72,9 @@ ec_node_str_complete(const struct ec_node *gen_node,
                struct ec_completed *completed,
                const struct ec_strvec *strvec)
 {
-       struct ec_completed_item *item = NULL;
        struct ec_node_str *node = (struct ec_node_str *)gen_node;
        const char *str;
        size_t n = 0;
-       int ret;
 
        if (ec_strvec_len(strvec) != 1)
                return 0;
@@ -91,19 +89,9 @@ ec_node_str_complete(const struct ec_node *gen_node,
        if (str[n] != '\0')
                return 0; // XXX add a no_match instead?
 
-       item = ec_completed_item(gen_node);
-       if (item == NULL)
-               return -ENOMEM;
-       ret = ec_completed_item_set(item, EC_COMP_FULL, node->string);
-       if (ret < 0) {
-               ec_completed_item_free(item);
-               return ret;
-       }
-       ret = ec_completed_item_add(completed, item);
-       if (ret < 0) {
-               ec_completed_item_free(item);
-               return ret;
-       }
+       if (ec_completed_add_item(completed, gen_node, NULL, EC_COMP_FULL,
+                                       str, node->string) < 0)
+               return -1;
 
        return 0;
 }
@@ -143,6 +131,11 @@ EC_NODE_TYPE_REGISTER(ec_node_str_type);
 int ec_node_str_set_str(struct ec_node *gen_node, const char *str)
 {
        struct ec_node_str *node = (struct ec_node_str *)gen_node;
+       int ret;
+
+       ret = ec_node_check_type(gen_node, &ec_node_str_type);
+       if (ret < 0)
+               return ret;
 
        if (str == NULL)
                return -EINVAL;
index b56bf81..8fe4b65 100644 (file)
@@ -181,7 +181,7 @@ __ec_node_subset_complete(struct ec_node **table, size_t table_len,
                        struct ec_completed *completed,
                        const struct ec_strvec *strvec)
 {
-       struct ec_parsed *parsed = ec_completed_cur_parse_state(completed);
+       struct ec_parsed *parsed = ec_completed_get_state(completed);
        struct ec_strvec *childvec = NULL;
        struct ec_node *save;
        size_t i, len;
index 3fb9db2..f7ca38f 100644 (file)
 
 TAILQ_HEAD(ec_parsed_list, ec_parsed);
 
+/* XXX idea for parse: maintain a "cursor" ?
+struct ec_parsed {
+   struct ec_parsed_tree *root;
+   stuct ec_parsed_tree *cursor;
+};
+*/
+
 struct ec_parsed {
        TAILQ_ENTRY(ec_parsed) next;
        struct ec_parsed_list children;
index 141c8cd..9dc0380 100644 (file)
@@ -63,15 +63,15 @@ static char *my_completion_entry(const char *s, int state)
 
        (void)s;
 
-       /* don't append a quote */
+       /* Don't append a quote. Note: there are still some bugs when
+        * completing a quoted token. */
        rl_completion_suppress_quote = 1;
-       rl_basic_quote_characters = "";
+       rl_completer_quote_characters = "\"'";
 
        if (state == 0) {
                char *line;
 
                ec_completed_free(c);
-
                line = strdup(rl_line_buffer);
                if (line == NULL)
                        return NULL;
@@ -83,7 +83,7 @@ static char *my_completion_entry(const char *s, int state)
                        return NULL;
 
                ec_completed_iter_free(iter);
-               iter = ec_completed_iter(c, EC_COMP_FULL | EC_PARTIAL_MATCH);
+               iter = ec_completed_iter(c, EC_COMP_FULL | EC_COMP_PARTIAL);
                if (iter == NULL)
                        return NULL;
        }
@@ -134,12 +134,10 @@ static char *get_node_help(const struct ec_completed_item *item)
        char *help = NULL;
        const char *node_help = NULL;
        const char *node_desc = NULL;
-//     size_t i;
 
-       (void)item;
-#if 1
        grp = ec_completed_item_get_grp(item);
        state = grp->state;
+       ec_parsed_dump(stdout, ec_parsed_get_root(state));
        for (state = grp->state; state != NULL;
             state = ec_parsed_get_parent(state)) {
                node = ec_parsed_get_node(state);
@@ -148,11 +146,6 @@ static char *get_node_help(const struct ec_completed_item *item)
                if (node_desc == NULL)
                        node_desc = ec_node_desc(node);
        }
-#else
-       node = ec_completed_item_get_node(item);
-       node_help = ec_keyval_get(ec_node_attrs(node), "help");
-       node_desc = ec_node_desc(node);
-#endif
 
        if (node_help == NULL)
                node_help = "-";
@@ -199,12 +192,12 @@ static int show_help(int ignore, int invoking_key)
        if (c == NULL)
                goto fail;
 
-       //ec_completed_dump(stdout, c);
+       ec_completed_dump(stdout, c);
 
        /* let's display one contextual help per node */
        count = 0;
        iter = ec_completed_iter(c,
-               EC_COMP_UNKNOWN | EC_COMP_FULL | EC_PARTIAL_MATCH);
+               EC_COMP_UNKNOWN | EC_COMP_FULL | EC_COMP_PARTIAL);
        if (iter == NULL)
                goto fail;
 
index 734de6b..7a73930 100644 (file)
@@ -322,6 +322,17 @@ changes:
   - ec_completed_item_set_display()
   - ec_completed_item_add()
 
+-----
+
+sh_lex
+  or
+    str(foo)
+    str(foo2)
+    str(bar)
+
+complete(sh_lex, ["'fo"])
+  complete(sh_lex, ["fo"]) -> ["foo", "foo2"]
+  
 
 -----