From e0aa24099c9c73831684689da1aa3c05e340e775 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Tue, 26 Sep 2017 15:44:53 +0200 Subject: [PATCH] save --- lib/Makefile | 1 + lib/ecoli_completed.c | 240 ++++++++++++++++++------------------------ lib/ecoli_completed.h | 25 ++--- lib/ecoli_node_file.c | 59 ++++++++--- lib/ecoli_node_str.c | 22 +++- lib/main-readline.c | 66 +++++------- lib/todo.txt | 3 + 7 files changed, 203 insertions(+), 213 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 8d44796..4bd4c94 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -68,6 +68,7 @@ srcs += ecoli_node_str.c srcs += ecoli_node_subset.c srcs += ecoli_node_weakref.c srcs += ecoli_parsed.c +srcs += ecoli_string.c srcs += ecoli_vec.c shlib-y-$(O)libecoli.so := $(srcs) diff --git a/lib/ecoli_completed.c b/lib/ecoli_completed.c index 728b284..64bb70d 100644 --- a/lib/ecoli_completed.c +++ b/lib/ecoli_completed.c @@ -82,12 +82,7 @@ ec_node_complete_child(struct ec_node *node, child_state->node = node; ec_parsed_add_child(parsed_state, child_state); - ret = ec_completed_add_node(completed, node); - if (ret < 0) - return ret; - - ret = node->type->complete(node, completed, - child_state, strvec); + ret = node->type->complete(node, completed, child_state, strvec); if (ret < 0) return ret; @@ -162,17 +157,6 @@ struct ec_completed *ec_node_complete(struct ec_node *node, return NULL; } -/* count the number of identical chars at the beginning of 2 strings */ -static size_t strcmp_count(const char *s1, const char *s2) -{ - size_t i = 0; - - while (s1[i] && s2[i] && s1[i] == s2[i]) - i++; - - return i; -} - static struct ec_completed_node * ec_completed_node(const struct ec_node *node) { @@ -188,7 +172,7 @@ ec_completed_node(const struct ec_node *node) return compnode; } -static struct ec_completed_item * +struct ec_completed_item * ec_completed_item(struct ec_parsed *state, const struct ec_node *node) { struct ec_completed_item *item = NULL; @@ -222,147 +206,162 @@ fail: if (item != NULL) { ec_free(item->path); ec_free(item->str); + ec_free(item->display); } ec_completed_item_free(item); return NULL; } -static int -__ec_completed_add_match(enum ec_completed_type type, - struct ec_completed *completed, - struct ec_parsed *parsed_state, - const struct ec_node *node, const char *str) +int +ec_completed_item_set(struct ec_completed_item *item, + enum ec_completed_type type, const char *str) { - struct ec_completed_node *compnode = NULL; - struct ec_completed_item *item = NULL; - int ret = -ENOMEM; + char *str_copy = NULL; + char *display_copy = NULL; + int ret = 0; - /* find the compnode entry corresponding to this node */ - TAILQ_FOREACH(compnode, &completed->nodes, next) { - if (compnode->node == node) - break; + if (item == NULL) + return -EINVAL; + if (item->str != NULL) + return -EEXIST; + + switch (type) { + case EC_NO_MATCH: + if (str != NULL) + return -EINVAL; + break; + case EC_MATCH: + case EC_PARTIAL_MATCH: + if (str == NULL) + return -EINVAL; + break; + default: + return -EINVAL; } - if (compnode == NULL) - return -ENOENT; - item = ec_completed_item(parsed_state, node); - if (item == NULL) - goto fail; - item->type = type; if (str != NULL) { - item->str = ec_strdup(str); - if (item->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; } - if (item->str != NULL) - completed->count_match++; - - TAILQ_INSERT_TAIL(&compnode->items, item, next); - completed->count++; - + item->type = type; + item->str = str_copy; + item->display = display_copy; return 0; fail: - ec_completed_item_free(item); + ec_free(str_copy); + ec_free(display_copy); return ret; } -int -ec_completed_add_match(struct ec_completed *completed, - struct ec_parsed *parsed_state, - const struct ec_node *node, const char *str) +int ec_completed_item_set_display(struct ec_completed_item *item, + const char *display) { - struct ec_completed_node *compnode = NULL; - struct ec_completed_item *item = NULL; - int ret = -ENOMEM; + char *display_copy = NULL; + int ret = 0; - /* find the compnode entry corresponding to this node */ - TAILQ_FOREACH(compnode, &completed->nodes, next) { - if (compnode->node == node) - break; - } - if (compnode == NULL) - return -ENOENT; + if (item == NULL || display == NULL || + item->type == EC_NO_MATCH || item->str == NULL) + return -EINVAL; - item = ec_completed_item(parsed_state, node); - if (item == NULL) + ret = -ENOMEM; + display_copy = ec_strdup(display); + if (display_copy == NULL) goto fail; - item->type = EC_MATCH; - if (str != NULL) { - item->str = ec_strdup(str); - if (item->str == NULL) - goto fail; - } - if (item->str != NULL) - completed->count_match++; - - TAILQ_INSERT_TAIL(&compnode->items, item, next); - completed->count++; + ec_free(item->display); + item->display = display_copy; return 0; fail: - ec_completed_item_free(item); + ec_free(display_copy); return ret; -} -int -ec_completed_add_no_match(struct ec_completed *completed, - struct ec_parsed *parsed_state, - const struct ec_node *node) -{ - return __ec_completed_add_match(EC_NO_MATCH, completed, parsed_state, - node, NULL); -} - -int -ec_completed_add_partial_match(struct ec_completed *completed, - struct ec_parsed *parsed_state, - const struct ec_node *node, const char *str) -{ - return __ec_completed_add_match(EC_PARTIAL_MATCH, completed, parsed_state, - node, str); } int -ec_completed_add_node(struct ec_completed *completed, - const struct ec_node *node) +ec_completed_item_add(struct ec_completed *completed, + struct ec_completed_item *item) { struct ec_completed_node *compnode = NULL; - compnode = ec_completed_node(node); - if (compnode == NULL) - return -ENOMEM; + if (completed == NULL || item == NULL || item->node == NULL) + return -EINVAL; + + switch (item->type) { + case EC_NO_MATCH: + break; + case EC_MATCH: + case EC_PARTIAL_MATCH: + completed->count_match++; //XXX + break; + default: + return -EINVAL; + } + + /* find the compnode entry corresponding to this node */ + TAILQ_FOREACH(compnode, &completed->nodes, next) { + if (compnode->node == item->node) + break; + } + if (compnode == NULL) { + compnode = ec_completed_node(item->node); + if (compnode == NULL) + return -ENOMEM; + TAILQ_INSERT_TAIL(&completed->nodes, compnode, next); + } + + completed->count++; + TAILQ_INSERT_TAIL(&compnode->items, item, next); - TAILQ_INSERT_TAIL(&completed->nodes, compnode, next); return 0; } -void ec_completed_item_free(struct ec_completed_item *match) +void ec_completed_item_free(struct ec_completed_item *item) { - ec_free(match->str); - ec_free(match->path); - ec_free(match); + if (item == NULL) + return; + + ec_free(item->str); + ec_free(item->display); + ec_free(item->path); + ec_free(item); } /* default completion function: return a no-match element */ int -ec_node_default_complete(const struct ec_node *gen_node, +ec_node_default_complete(const struct ec_node *gen_node, // XXX rename in nomatch struct ec_completed *completed, struct ec_parsed *parsed_state, const struct ec_strvec *strvec) { + struct ec_completed_item *item = NULL; int ret; if (ec_strvec_len(strvec) != 1) return 0; - ret = ec_completed_add_no_match(completed, parsed_state, gen_node); - if (ret < 0) + item = ec_completed_item(parsed_state, gen_node); + if (item == NULL) + return -ENOMEM; + ret = ec_completed_item_set(item, EC_NO_MATCH, 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); + return ret; + } return 0; } @@ -415,41 +414,10 @@ void ec_completed_dump(FILE *out, const struct ec_completed *completed) default: typestr = "unknown"; break; } - fprintf(out, " type=%s str=<%s>\n", typestr, item->str); - } - } -} - -char *ec_completed_smallest_start(const struct ec_completed *completed) -{ - struct ec_completed_node *compnode; - struct ec_completed_item *item; - char *smallest_start = NULL; - size_t n; - - if (completed == NULL) - goto fail; - - TAILQ_FOREACH(compnode, &completed->nodes, next) { - TAILQ_FOREACH(item, &compnode->items, next) { - if (item->str == NULL) - continue; - if (smallest_start == NULL) { - smallest_start = ec_strdup(item->str); - if (smallest_start == NULL) - goto fail; - } else { - n = strcmp_count(item->str, smallest_start); - smallest_start[n] = '\0'; - } + fprintf(out, " type=%s str=<%s> disp=<%s>\n", + typestr, item->str, item->display); } } - - return smallest_start; - -fail: - ec_free(smallest_start); - return NULL; } unsigned int ec_completed_count( diff --git a/lib/ecoli_completed.h b/lib/ecoli_completed.h index 39816bb..16c79a6 100644 --- a/lib/ecoli_completed.h +++ b/lib/ecoli_completed.h @@ -45,6 +45,7 @@ struct ec_completed_item { enum ec_completed_type type; const struct ec_node *node; char *str; + char *display; /* reverse order: [0] = last, [len-1] = root */ const struct ec_node **path; @@ -84,20 +85,17 @@ int ec_node_complete_child(struct ec_node *node, struct ec_completed *ec_completed(void); -int ec_completed_add_match(struct ec_completed *completed, - struct ec_parsed *state, - const struct ec_node *node, const char *add); -int ec_completed_add_no_match(struct ec_completed *completed, - struct ec_parsed *parsed_state, - const struct ec_node *node); -int ec_completed_add_partial_match(struct ec_completed *completed, - struct ec_parsed *state, const struct ec_node *node, - const char *add); +struct ec_completed_item * +ec_completed_item(struct ec_parsed *state, const struct ec_node *node); +int ec_completed_item_set(struct ec_completed_item *item, + enum ec_completed_type type, const char *str); +int ec_completed_item_add(struct ec_completed *completed, + struct ec_completed_item *item); +void ec_completed_item_free(struct ec_completed_item *item); -int ec_completed_add_node(struct ec_completed *completed, - const struct ec_node *node); +int ec_completed_item_set_display(struct ec_completed_item *item, + const char *display); -void ec_completed_item_free(struct ec_completed_item *item); void ec_completed_free(struct ec_completed *completed); void ec_completed_dump(FILE *out, const struct ec_completed *completed); @@ -107,9 +105,6 @@ ec_node_default_complete(const struct ec_node *gen_node, struct ec_parsed *state, const struct ec_strvec *strvec); -/* return the smallest string start, or NULL on error */ -char *ec_completed_smallest_start(const struct ec_completed *completed); - unsigned int ec_completed_count( const struct ec_completed *completed, enum ec_completed_type flags); diff --git a/lib/ecoli_node_file.c b/lib/ecoli_node_file.c index 0a5caa3..51badf7 100644 --- a/lib/ecoli_node_file.c +++ b/lib/ecoli_node_file.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -116,13 +117,15 @@ ec_node_file_complete(const struct ec_node *gen_node, struct ec_parsed *state, const struct ec_strvec *strvec) { + struct ec_completed_item *item = NULL; struct stat st; - const char *path; + const char *input; size_t bname_len; struct dirent *de = NULL; DIR *dir = NULL; char *dname = NULL, *bname = NULL, *effective_dir; - char *add = NULL; + char *comp_str = NULL; + char *disp_str = NULL; int ret; int is_dir = 0; @@ -151,8 +154,8 @@ ec_node_file_complete(const struct ec_node *gen_node, if (ec_strvec_len(strvec) != 1) goto out; - path = ec_strvec_val(strvec, 0); - ret = split_path(path, &dname, &bname); + input = ec_strvec_val(strvec, 0); + ret = split_path(input, &dname, &bname); if (ret < 0) { ec_completed_free(completed); completed = NULL; @@ -182,7 +185,7 @@ ec_node_file_complete(const struct ec_node *gen_node, if (de == NULL) goto out; - if (strncmp(bname, de->d_name, bname_len)) + if (!ec_str_startswith(de->d_name, bname)) continue; if (bname[0] != '.' && de->d_name[0] == '.') continue; @@ -195,36 +198,60 @@ ec_node_file_complete(const struct ec_node *gen_node, is_dir = 0; } + item = ec_completed_item(state, gen_node); + if (item == NULL) { + ret = -ENOMEM; + goto out; + } + if (is_dir) { - if (asprintf(&add, "%s%s/", path, + if (asprintf(&comp_str, "%s%s/", input, &de->d_name[bname_len]) < 0) { ret = -errno; goto out; } - if (ec_completed_add_partial_match( - completed, state, gen_node, add) < 0) { - ec_completed_free(completed); - completed = NULL; + if (asprintf(&disp_str, "%s/", de->d_name) < 0) { + ret = -errno; goto out; } + ret = ec_completed_item_set(item, EC_PARTIAL_MATCH, + comp_str); + if (ret < 0) + goto out; } else { - if (asprintf(&add, "%s%s", path, + if (asprintf(&comp_str, "%s%s", input, &de->d_name[bname_len]) < 0) { ret = -errno; goto out; } - if (ec_completed_add_match(completed, state, gen_node, - add) < 0) { - ec_completed_free(completed); - completed = NULL; + if (asprintf(&disp_str, "%s", de->d_name) < 0) { + ret = -errno; goto out; } + ret = ec_completed_item_set(item, EC_MATCH, + comp_str); + if (ret < 0) + goto out; } + ret = ec_completed_item_set_display(item, disp_str); + if (ret < 0) + goto out; + ret = ec_completed_item_add(completed, item); + if (ret < 0) + goto out; + + item = NULL; + free(comp_str); + comp_str = NULL; + free(disp_str); + disp_str = NULL; } ret = 0; out: - free(add); + ec_completed_item_free(item); + free(comp_str); + free(disp_str); ec_free(dname); ec_free(bname); if (dir != NULL) diff --git a/lib/ecoli_node_str.c b/lib/ecoli_node_str.c index b846448..0069c83 100644 --- a/lib/ecoli_node_str.c +++ b/lib/ecoli_node_str.c @@ -71,9 +71,11 @@ ec_node_str_complete(const struct ec_node *gen_node, struct ec_parsed *parsed, 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; (void)parsed; @@ -86,10 +88,22 @@ ec_node_str_complete(const struct ec_node *gen_node, break; } - if (str[n] == '\0') { - if (ec_completed_add_match(completed, parsed, gen_node, - node->string) < 0) - return -1; + /* no completion */ + if (str[n] != '\0') + return 0; // XXX add a no_match instead? + + item = ec_completed_item(parsed, gen_node); + if (item == NULL) + return -ENOMEM; + ret = ec_completed_item_set(item, EC_MATCH, 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; } return 0; diff --git a/lib/main-readline.c b/lib/main-readline.c index 6133c54..a63adfc 100644 --- a/lib/main-readline.c +++ b/lib/main-readline.c @@ -88,17 +88,22 @@ static char *my_completion_entry(const char *s, int state) if (item == NULL) return NULL; - /* don't add the trailing space for partial completions */ - if (state == 0) { - if (item->type == EC_MATCH) - rl_completion_suppress_append = 0; - else - rl_completion_suppress_append = 1; + if (c->count_match == 1) { + + /* don't add the trailing space for partial completions */ + if (state == 0) { + if (item->type == EC_MATCH) + rl_completion_suppress_append = 0; + else + rl_completion_suppress_append = 1; + } + + return strdup(item->str); + } else if (rl_completion_type == '?') { + /* on second try only show the display part */ + return strdup(item->display); } - //XXX see printable_part() and rl_display_match_list() - //XXX or: if match count > 1, strip beginning (in node_file) - return strdup(item->str); } @@ -114,14 +119,19 @@ static char **my_attempted_completion(const char *text, int start, int end) } /* this function builds the help string */ -static char *get_node_help(const struct ec_completed_item *item) +static char *get_node_help(const struct ec_completed_node *compnode) { + const struct ec_completed_item *item; const struct ec_node *node; char *help = NULL; const char *node_help = NULL; const char *node_desc = NULL; size_t i; + /* Since we display only one help per node, only look at the first item + * to get the path. The objective is to retrieve the most precise + * help for this node. */ + item = TAILQ_FIRST(&compnode->items); for (i = 0; i < item->pathlen; i++) { node = item->path[i]; if (node_help == NULL) @@ -144,8 +154,6 @@ static char *get_node_help(const struct ec_completed_item *item) static int show_help(int ignore, int invoking_key) { const struct ec_completed_node *compnode; -// const struct ec_completed_item *item; -// struct ec_completed_iter *iter; struct ec_completed *c; struct ec_parsed *p; char *line; @@ -174,28 +182,7 @@ static int show_help(int ignore, int invoking_key) if (c == NULL) return 1; -#if 0 // old method - count = ec_completed_count(c, EC_MATCH | EC_NO_MATCH | - EC_PARTIAL_MATCH); - 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 | - EC_PARTIAL_MATCH); - if (iter == NULL) - goto fail; - - /* strangely, rl_display_match_list() expects first index at 1 */ - for (i = match + 1, item = ec_completed_iter_next(iter); - i < count + match + 1 && item != NULL; - i++, item = ec_completed_iter_next(iter)) { - helps[i] = get_node_help(item); - } -#else + /* let's display one contextual help per node */ count = 0; TAILQ_FOREACH(compnode, &c->nodes, next) { if (TAILQ_EMPTY(&compnode->items)) @@ -215,10 +202,8 @@ static int show_help(int ignore, int invoking_key) TAILQ_FOREACH(compnode, &c->nodes, next) { if (TAILQ_EMPTY(&compnode->items)) continue; - // we should pass compnode instead - helps[i++] = get_node_help(TAILQ_FIRST(&compnode->items)); //XXX + helps[i++] = get_node_help(compnode); } -#endif ec_completed_dump(stdout, c); ec_completed_free(c); @@ -229,10 +214,7 @@ static int show_help(int ignore, int invoking_key) return 0; -//fail: - free(helps); - // free helps[n] XXX - return 1; + // free helps[n] XXX on error ? } static int create_commands(void) @@ -262,7 +244,7 @@ static int create_commands(void) ec_keyval_set(ec_node_attrs(ec_node_find(cmd, "name")), "help", "the name of the person", NULL); ec_keyval_set(ec_node_attrs(ec_node_find(cmd, "int")), - "help", "an integer", NULL); + "help", "an integer (0-10)", NULL); if (ec_node_or_add(cmdlist, cmd) < 0) goto fail; diff --git a/lib/todo.txt b/lib/todo.txt index 37a61d7..8d56dc5 100644 --- a/lib/todo.txt +++ b/lib/todo.txt @@ -9,6 +9,9 @@ X tk_re cleanup / rework ================ +- ec_completed_item_update() +- ec_completed_item_set_display_value() + - add_no_match - add_partial_match - check XXX in code -- 2.20.1