From 4af8db90e825a2e6dd7034ec88fd6f856bf83e9e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 6 Jan 2009 17:04:56 +0000 Subject: [PATCH] Complete option names as well. --- CHANGES | 4 +- TODO | 4 +- cmd.c | 53 +----------------------- status.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++------ tmux.h | 3 +- 5 files changed, 118 insertions(+), 70 deletions(-) diff --git a/CHANGES b/CHANGES index acf1a7a2..303375a1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,7 @@ 06 January 2009 +* Complete words at any point inside command in prompt, also use option name + as well as command names. * Per-client prompt history of up to 100 items. * Use a splay tree for key bindings instead of an array. As a side-effect this sorts them when listed. @@ -798,7 +800,7 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.178 2009-01-06 15:37:15 nicm Exp $ +$Id: CHANGES,v 1.179 2009-01-06 17:04:56 nicm Exp $ LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB diff --git a/TODO b/TODO index 99e56002..3571bba9 100644 --- a/TODO +++ b/TODO @@ -44,9 +44,7 @@ session not being watched? - tidy up window modes - problems with force-width when wrapping line in emacs? -- command history for command-prompt. better tab completion (use options too) -- window options should be done similarly to standard options -- next prev word etc in command prompt +- next prev word etc in command prompt; also ^K - many more info() displays for various things - vi half page scroll - document status line options, title bits diff --git a/cmd.c b/cmd.c index 4f4cf631..d9d46a40 100644 --- a/cmd.c +++ b/cmd.c @@ -1,4 +1,4 @@ -/* $Id: cmd.c,v 1.67 2008-12-15 21:21:56 nicm Exp $ */ +/* $Id: cmd.c,v 1.68 2009-01-06 17:04:56 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -74,57 +74,6 @@ const struct cmd_entry *cmd_table[] = { NULL }; -char * -cmd_complete(const char *s) -{ - const struct cmd_entry **entryp; - ARRAY_DECL(, const char *) list; - char *prefix, *s2; - u_int i; - size_t j; - - if (*s == '\0') - return (xstrdup(s)); - - /* First, build a list of all the possible matches. */ - ARRAY_INIT(&list); - for (entryp = cmd_table; *entryp != NULL; entryp++) { - if (strncmp((*entryp)->name, s, strlen(s)) != 0) - continue; - ARRAY_ADD(&list, (*entryp)->name); - } - - /* If none, bail now with the original string. */ - if (ARRAY_LENGTH(&list) == 0) { - ARRAY_FREE(&list); - return (xstrdup(s)); - } - - /* If an exact match, return it, with a trailing space. */ - if (ARRAY_LENGTH(&list) == 1) { - xasprintf(&s2, "%s ", ARRAY_FIRST(&list)); - ARRAY_FREE(&list); - return (s2); - } - - /* Now loop through the list and find the longest common prefix. */ - prefix = xstrdup(ARRAY_FIRST(&list)); - for (i = 1; i < ARRAY_LENGTH(&list); i++) { - s = ARRAY_ITEM(&list, i); - - j = strlen(s); - if (j > strlen(prefix)) - j = strlen(prefix); - for (; j > 0; j--) { - if (prefix[j - 1] != s[j - 1]) - prefix[j - 1] = '\0'; - } - } - - ARRAY_FREE(&list); - return (prefix); -} - struct cmd * cmd_parse(int argc, char **argv, char **cause) { diff --git a/status.c b/status.c index dde750aa..528f4299 100644 --- a/status.c +++ b/status.c @@ -1,4 +1,4 @@ -/* $Id: status.c,v 1.53 2009-01-06 15:37:15 nicm Exp $ */ +/* $Id: status.c,v 1.54 2009-01-06 17:04:56 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -33,6 +33,7 @@ size_t status_width(struct winlink *); char *status_print(struct session *, struct winlink *, struct grid_cell *); void status_prompt_add_history(struct client *); +char *status_prompt_complete(const char *); /* Draw status for client on the last lines of given context. */ void @@ -225,9 +226,10 @@ draw: gc.attr |= GRID_ATTR_REVERSE; else gc.attr &= ~GRID_ATTR_REVERSE; - if (rlen != 0) - ctx.write(ctx.data, TTY_CURSORMOVE, c->sx - rlen - 2, yy); - else + if (rlen != 0) { + ctx.write( + ctx.data, TTY_CURSORMOVE, c->sx - rlen - 2, yy); + } else ctx.write(ctx.data, TTY_CURSORMOVE, c->sx - 1, yy); screen_redraw_putc(&ctx, &gc, '>'); gc.attr &= ~GRID_ATTR_REVERSE; @@ -467,8 +469,9 @@ status_prompt_redraw(struct client *c) void status_prompt_key(struct client *c, int key) { - char *s; - size_t size; + char *s, *first, *last; + size_t size, n, off, idx; + char word[64]; size = strlen(c->prompt_buffer); switch (key) { @@ -497,16 +500,51 @@ status_prompt_key(struct client *c, int key) } break; case '\011': - if (strchr(c->prompt_buffer, ' ') != NULL) + if (*c->prompt_buffer == '\0') break; - if (c->prompt_index != strlen(c->prompt_buffer)) + + idx = c->prompt_index; + if (idx != 0) + idx--; + + /* Find the word we are in. */ + first = c->prompt_buffer + idx; + while (first > c->prompt_buffer && *first != ' ') + first--; + while (*first == ' ') + first++; + last = c->prompt_buffer + idx; + while (*last != '\0' && *last != ' ') + last++; + while (*last == ' ') + last--; + if (*last != '\0') + last++; + if (last <= first || last - first > (sizeof word) - 1) + break; + memcpy(word, first, last - first); + word[last - first] = '\0'; + + /* And try to complete it. */ + if ((s = status_prompt_complete(word)) == NULL) break; - s = cmd_complete(c->prompt_buffer); - xfree(c->prompt_buffer); + log_debug("XXX '%s' '%s' '%s'", c->prompt_buffer, first, last); - c->prompt_buffer = s; - c->prompt_index = strlen(c->prompt_buffer); + /* Trim out word. */ + n = size - (last - c->prompt_buffer) + 1; /* with \0 */ + memmove(first, last, n); + size -= last - first; + + /* Insert the new word. */ + size += strlen(s); + off = first - c->prompt_buffer; + c->prompt_buffer = xrealloc(c->prompt_buffer, 1, size + 1); + first = c->prompt_buffer + off; + memmove(first + strlen(s), first, n); + memcpy(first, s, strlen(s)); + + c->prompt_index = (first - c->prompt_buffer) + strlen(s); c->flags |= CLIENT_STATUS; break; @@ -607,3 +645,65 @@ status_prompt_add_history(struct client *c) ARRAY_ADD(&c->prompt_hdata, xstrdup(c->prompt_buffer)); } + +/* Complete word. */ +char * +status_prompt_complete(const char *s) +{ + const struct cmd_entry **cmdent; + const struct set_option_entry *optent; + ARRAY_DECL(, const char *) list; + char *prefix, *s2; + u_int i; + size_t j; + + if (*s == '\0') + return (NULL); + + /* First, build a list of all the possible matches. */ + ARRAY_INIT(&list); + for (cmdent = cmd_table; *cmdent != NULL; cmdent++) { + if (strncmp((*cmdent)->name, s, strlen(s)) == 0) + ARRAY_ADD(&list, (*cmdent)->name); + } + for (i = 0; i < NSETOPTION; i++) { + optent = &set_option_table[i]; + if (strncmp(optent->name, s, strlen(s)) == 0) + ARRAY_ADD(&list, optent->name); + } + for (i = 0; i < NSETWINDOWOPTION; i++) { + optent = &set_window_option_table[i]; + if (strncmp(optent->name, s, strlen(s)) == 0) + ARRAY_ADD(&list, optent->name); + } + + /* If none, bail now. */ + if (ARRAY_LENGTH(&list) == 0) { + ARRAY_FREE(&list); + return (NULL); + } + + /* If an exact match, return it, with a trailing space. */ + if (ARRAY_LENGTH(&list) == 1) { + xasprintf(&s2, "%s ", ARRAY_FIRST(&list)); + ARRAY_FREE(&list); + return (s2); + } + + /* Now loop through the list and find the longest common prefix. */ + prefix = xstrdup(ARRAY_FIRST(&list)); + for (i = 1; i < ARRAY_LENGTH(&list); i++) { + s = ARRAY_ITEM(&list, i); + + j = strlen(s); + if (j > strlen(prefix)) + j = strlen(prefix); + for (; j > 0; j--) { + if (prefix[j - 1] != s[j - 1]) + prefix[j - 1] = '\0'; + } + } + + ARRAY_FREE(&list); + return (prefix); +} diff --git a/tmux.h b/tmux.h index 8f891079..d709c18d 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.206 2009-01-06 15:37:15 nicm Exp $ */ +/* $Id: tmux.h,v 1.207 2009-01-06 17:04:56 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -1009,7 +1009,6 @@ struct session *arg_parse_session(const char *); int arg_parse_window(const char *, struct session **, int *); /* cmd.c */ -char *cmd_complete(const char *); struct cmd *cmd_parse(int, char **, char **); void cmd_exec(struct cmd *, struct cmd_ctx *); void cmd_send(struct cmd *, struct buffer *);