X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Fmain-readline.c;h=73df238f8f23e6d1eb1ef469ce9671fce91e4f5a;hb=90d09f5806b457e758ac7f4fadf485d24162d38f;hp=3bdc70322bd05d39e7706f3471cfeeb6f52190b1;hpb=ae2c4709444ee6fbbf388b853ab4039fcdde2e95;p=protos%2Flibecoli.git diff --git a/lib/main-readline.c b/lib/main-readline.c index 3bdc703..73df238 100644 --- a/lib/main-readline.c +++ b/lib/main-readline.c @@ -25,6 +25,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define _GNU_SOURCE /* for asprintf */ #include #include #include @@ -32,87 +33,214 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -static struct ec_tk *commands; +static struct ec_node *commands; -/* Set to a character describing the type of completion being attempted by - rl_complete_internal; available for use by application completion - functions. */ -extern int rl_completion_type; -/* Set to the last key used to invoke one of the completion functions */ -extern int rl_completion_invoking_key; - -int my_complete(int x, int y) -{ - (void)x; - (void)y; - - return 0; -} - -char *my_completion_entry(const char *s, int state) +static char *my_completion_entry(const char *s, int state) { - static struct ec_completed_tk *c; - static const struct ec_completed_tk_elt *elt; + static struct ec_completed *c; + static struct ec_completed_iter *iter; + static const struct ec_completed_elt *elt; + char *out_string; - (void)s; if (state == 0) { - char *start; + char *line; - if (c != NULL) - ec_completed_tk_free(c); + ec_completed_free(c); - start = strdup(rl_line_buffer); - if (start == NULL) + line = strdup(rl_line_buffer); + if (line == NULL) return NULL; - start[rl_point] = '\0'; + line[rl_point] = '\0'; - c = ec_tk_complete(commands, start); - ec_completed_tk_iter_start(c); + c = ec_node_complete(commands, line); + free(line); + if (c == NULL) + return NULL; + + ec_completed_iter_free(iter); + iter = ec_completed_iter(c, EC_MATCH); + if (iter == NULL) + return NULL; } - elt = ec_completed_tk_iter_next(c); + elt = ec_completed_iter_next(iter); if (elt == NULL) return NULL; - return strdup(elt->full); + if (asprintf(&out_string, "%s%s", s, elt->add) < 0) + return NULL; + + return out_string; } -char **my_attempted_completion(const char *text, int start, int end) +static char **my_attempted_completion(const char *text, int start, int end) { (void)start; (void)end; - // XXX when it returns NULL, it completes with a file + + /* remove default file completion */ + rl_attempted_completion_over = 1; + return rl_completion_matches(text, my_completion_entry); } -int main(void) +/* this function builds the help string */ +static char *get_tk_help(const struct ec_node *node) { - struct ec_parsed_tk *p; -// const char *name; + const struct ec_node *node2; + char *help = NULL; + char *tk_help = NULL; + + for (node2 = node; + node2 != NULL && tk_help == NULL; + node2 = ec_node_parent(node2)) + tk_help = ec_keyval_get(ec_node_attrs(node2), "help"); + + if (tk_help == NULL) + tk_help = ""; + + if (asprintf(&help, "%-20s %s", ec_node_desc(node), tk_help) < 0) + return NULL; + + return help; +} + +static int show_help(int ignore, int invoking_key) +{ + const struct ec_completed_elt *elt; + struct ec_completed_iter *iter; + struct ec_completed *c; char *line; + unsigned int count, i; + char **helps = NULL; + + (void)ignore; + (void)invoking_key; + + line = strdup(rl_line_buffer); + if (line == NULL) + return 1; + line[rl_point] = '\0'; + + c = ec_node_complete(commands, line); + free(line); + if (c == NULL) + return 1; + //ec_completed_dump(stdout, c); - commands = ec_tk_seq_new_list(NULL, - ec_tk_str_new(NULL, "hello"), - ec_tk_space_new(NULL), - ec_tk_or_new_list("name", - ec_tk_str_new(NULL, "john"), - ec_tk_str_new(NULL, "mike"), - EC_TK_ENDLIST), - EC_TK_ENDLIST); - if (commands == NULL) { - printf("cannot create token\n"); + count = ec_completed_count(c, EC_MATCH | EC_NO_MATCH); + helps = calloc(count + 1, sizeof(char *)); + if (helps == NULL) return 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; + i++, elt = ec_completed_iter_next(iter)) { + helps[i] = get_tk_help(elt->node); } - //rl_bind_key('\t', my_complete); + ec_completed_free(c); + + rl_display_match_list(helps, count, 1000); + + rl_forced_update_display(); + + return 0; + +fail: + free(helps); + // free helps[n] XXX + return 1; +} + +static int create_commands(void) +{ + struct ec_node *cmdlist = NULL, *cmd = NULL; + + cmdlist = ec_node("or", NULL); + if (cmdlist == NULL) + goto fail; + + cmd = EC_NODE_SEQ(NULL, + ec_node_str(NULL, "hello"), + EC_NODE_OR("name", + ec_node_str(NULL, "john"), + ec_node_str(NULL, "johnny"), + ec_node_str(NULL, "mike") + ), + ec_node_option(NULL, ec_node_int("int", 0, 10, 10)) + ); + if (cmd == NULL) + goto fail; + ec_keyval_set(ec_node_attrs(cmd), "help", + "say hello to someone several times", NULL); + 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); + if (ec_node_or_add(cmdlist, cmd) < 0) + goto fail; + +#if 0 + cmd = EC_NODE_CMD(NULL, "good morning john|johnny|mike [count]", + ec_node_int("count", 0, 10, 10)); + if (cmd == NULL) + goto fail; + ec_keyval_set(ec_node_attrs(cmd), "help", + "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") + ); + ec_keyval_set(ec_node_attrs(cmd), "help", "say bye to someone", NULL); + if (ec_node_or_add(cmdlist, cmd) < 0) + goto fail; - //rl_completion_entry_function = my_completion_entry; + commands = ec_node_sh_lex(NULL, cmdlist); + if (commands == NULL) + goto fail; + + return 0; + + fail: + fprintf(stderr, "cannot initialize nodes\n"); + ec_node_free(cmdlist); + return -1; +} + +int main(void) +{ + struct ec_parsed *p; +// const char *name; + char *line; + + + if (create_commands() < 0) + return 1; + + rl_bind_key('?', show_help); rl_attempted_completion_function = my_attempted_completion; while (1) { @@ -120,14 +248,14 @@ int main(void) if (line == NULL) break; - // XXX need a "parse_all" - p = ec_tk_parse(commands, line); - ec_parsed_tk_dump(stdout, p); + p = ec_node_parse(commands, line); + ec_parsed_dump(stdout, p); add_history(line); - ec_parsed_tk_free(p); + ec_parsed_free(p); } - ec_tk_free(commands); + ec_node_free(commands); return 0; + }