diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index e53c4320..b8e3bd5c 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -40,8 +40,8 @@ const struct cmd_entry cmd_command_prompt_entry = { .name = "command-prompt", .alias = NULL, - .args = { "1kiI:Np:t:", 0, 1 }, - .usage = "[-1kiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " " + .args = { "1kiI:Np:Tt:W", 0, 1 }, + .usage = "[-1kiNTW] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " " "[template]", .flags = CMD_CLIENT_TFLAG, @@ -121,6 +121,10 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) cdata->flags |= PROMPT_INCREMENTAL; else if (args_has(args, 'k')) cdata->flags |= PROMPT_KEY; + else if (args_has(args, 'W')) + cdata->flags |= PROMPT_WINDOW; + else if (args_has(args, 'T')) + cdata->flags |= PROMPT_TARGET; status_prompt_set(tc, prompt, input, cmd_command_prompt_callback, cmd_command_prompt_free, cdata, cdata->flags); free(prompt); diff --git a/key-bindings.c b/key-bindings.c index 09a4eafa..85bfb788 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -243,12 +243,12 @@ key_bindings_init(void) "bind -N 'Rename current session' '$' command-prompt -I'#S' \"rename-session -- '%%'\"", "bind -N 'Split window horizontally' % split-window -h", "bind -N 'Kill current window' & confirm-before -p\"kill-window #W? (y/n)\" kill-window", - "bind -N 'Prompt for window index to select' \"'\" command-prompt -pindex \"select-window -t ':%%'\"", + "bind -N 'Prompt for window index to select' \"'\" command-prompt -Wpindex \"select-window -t ':%%'\"", "bind -N 'Switch to previous client' ( switch-client -p", "bind -N 'Switch to next client' ) switch-client -n", "bind -N 'Rename current window' , command-prompt -I'#W' \"rename-window -- '%%'\"", "bind -N 'Delete the most recent paste buffer' - delete-buffer", - "bind -N 'Move the current window' . command-prompt \"move-window -t '%%'\"", + "bind -N 'Move the current window' . command-prompt -T \"move-window -t '%%'\"", "bind -N 'Describe key binding' '/' command-prompt -kpkey 'list-keys -1N \"%%%\"'", "bind -N 'Select window 0' 0 select-window -t:=0", "bind -N 'Select window 1' 1 select-window -t:=1", diff --git a/status.c b/status.c index 712a93df..77b92717 100644 --- a/status.c +++ b/status.c @@ -38,6 +38,8 @@ static const char *status_prompt_down_history(u_int *); static void status_prompt_add_history(const char *); static char *status_prompt_complete(struct client *, const char *, u_int); +static char *status_prompt_complete_window_menu(struct client *, + struct session *, u_int, char); struct status_prompt_menu { struct client *c; @@ -933,13 +935,11 @@ status_prompt_replace_complete(struct client *c, const char *s) size_t size, n, off, idx, used; struct utf8_data *first, *last, *ud; - if (c->prompt_buffer[0].size == 0) - return (0); - size = utf8_strlen(c->prompt_buffer); - + /* Work out where the cursor currently is. */ idx = c->prompt_index; if (idx != 0) idx--; + size = utf8_strlen(c->prompt_buffer); /* Find the word we are in. */ first = &c->prompt_buffer[idx]; @@ -954,7 +954,7 @@ status_prompt_replace_complete(struct client *c, const char *s) last--; if (last->size != 0) last++; - if (last <= first) + if (last < first) return (0); if (s == NULL) { used = 0; @@ -1071,7 +1071,15 @@ process_key: } break; case '\011': /* Tab */ - if (status_prompt_replace_complete(c, NULL)) + if (c->prompt_flags & PROMPT_WINDOW) { + s = status_prompt_complete_window_menu(c, c->session, + 0, '\0'); + if (s != NULL) { + free(c->prompt_buffer); + c->prompt_buffer = utf8_fromcstr(s); + c->prompt_index = utf8_strlen(c->prompt_buffer); + } + } else if (status_prompt_replace_complete(c, NULL)) goto changed; break; case KEYC_BSPACE: @@ -1455,7 +1463,12 @@ status_prompt_menu_callback(__unused struct menu *menu, u_int idx, key_code key, s = xstrdup(spm->list[idx]); else xasprintf(&s, "-%c%s", spm->flag, spm->list[idx]); - if (status_prompt_replace_complete(c, s)) + if (c->prompt_flags & PROMPT_WINDOW) { + free(c->prompt_buffer); + c->prompt_buffer = utf8_fromcstr(s); + c->prompt_index = utf8_strlen(c->prompt_buffer); + c->flags |= CLIENT_REDRAWSTATUS; + } else if (status_prompt_replace_complete(c, s)) c->flags |= CLIENT_REDRAWSTATUS; free(s); } @@ -1549,10 +1562,14 @@ status_prompt_complete_window_menu(struct client *c, struct session *s, menu = menu_create(""); RB_FOREACH(wl, winlinks, &s->windows) { list = xreallocarray(list, size + 1, sizeof *list); - xasprintf(&list[size++], "%s:%d", s->name, wl->idx); - - xasprintf(&tmp, "%s:%d (%s)", s->name, wl->idx, - wl->window->name); + if (c->prompt_flags & PROMPT_WINDOW) { + xasprintf(&tmp, "%d (%s)", wl->idx, wl->window->name); + xasprintf(&list[size++], "%d", wl->idx); + } else { + xasprintf(&tmp, "%s:%d (%s)", s->name, wl->idx, + wl->window->name); + xasprintf(&list[size++], "%s:%d", s->name, wl->idx); + } item.name = tmp; item.key = '0' + size - 1; item.command = NULL; @@ -1564,8 +1581,11 @@ status_prompt_complete_window_menu(struct client *c, struct session *s, } if (size == 1) { menu_free(menu); - xasprintf(&tmp, "-%c%s", flag, list[0]); - free(list[0]); + if (flag != '\0') { + xasprintf(&tmp, "-%c%s", flag, list[0]); + free(list[0]); + } else + tmp = list[0]; free(list); return (tmp); } @@ -1603,21 +1623,45 @@ status_prompt_complete_sort(const void *a, const void *b) return (strcmp(*aa, *bb)); } +/* Complete a session. */ +static char * +status_prompt_complete_session(char ***list, u_int *size, const char *s, + char flag) +{ + struct session *loop; + char *out, *tmp; + + RB_FOREACH(loop, sessions, &sessions) { + if (*s != '\0' && strncmp(loop->name, s, strlen(s)) != 0) + continue; + *list = xreallocarray(*list, (*size) + 2, sizeof **list); + xasprintf(&(*list)[(*size)++], "%s:", loop->name); + } + out = status_prompt_complete_prefix(*list, *size); + if (out != NULL && flag != '\0') { + xasprintf(&tmp, "-%c%s", flag, out); + free(out); + out = tmp; + } + return (out); +} + /* Complete word. */ static char * status_prompt_complete(struct client *c, const char *word, u_int offset) { - struct session *session, *loop; + struct session *session; const char *s, *colon; - size_t slen; - char **list = NULL, *copy = NULL, *out = NULL, *tmp; + char **list = NULL, *copy = NULL, *out = NULL; char flag = '\0'; u_int size = 0, i; - if (*word == '\0') + if (*word == '\0' && (~c->prompt_flags & PROMPT_TARGET)) return (NULL); - if (strncmp(word, "-t", 2) != 0 && strncmp(word, "-s", 2) != 0) { + if ((~c->prompt_flags & PROMPT_TARGET) && + strncmp(word, "-t", 2) != 0 && + strncmp(word, "-s", 2) != 0) { list = status_prompt_complete_list(&size, word, offset == 0); if (size == 0) out = NULL; @@ -1628,28 +1672,19 @@ status_prompt_complete(struct client *c, const char *word, u_int offset) goto found; } - s = word + 2; - slen = strlen(s); - - flag = word[1]; - offset += 2; - + if (c->prompt_flags & PROMPT_TARGET) { + s = word; + flag = '\0'; + } else { + s = word + 2; + flag = word[1]; + offset += 2; + } colon = strchr(s, ':'); /* If there is no colon, complete as a session. */ if (colon == NULL) { - RB_FOREACH(loop, sessions, &sessions) { - if (strncmp(loop->name, s, strlen(s)) != 0) - continue; - list = xreallocarray(list, size + 2, sizeof *list); - xasprintf(&list[size++], "%s:", loop->name); - } - out = status_prompt_complete_prefix(list, size); - if (out != NULL) { - xasprintf(&tmp, "-%c%s", flag, out); - free(out); - out = tmp; - } + out = status_prompt_complete_session(&list, &size, s, flag); goto found; } diff --git a/tmux.1 b/tmux.1 index c85e7e39..198f5660 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4969,7 +4969,7 @@ session option. Commands related to the status line are as follows: .Bl -tag -width Ds .It Xo Ic command-prompt -.Op Fl 1ikN +.Op Fl 1ikNTW .Op Fl I Ar inputs .Op Fl p Ar prompts .Op Fl t Ar target-client @@ -5028,6 +5028,14 @@ makes the prompt only accept numeric key presses. .Fl i executes the command every time the prompt input changes instead of when the user exits the command prompt. +.Fl T +tells +.Nm +that the prompt is for a target which affects what completions are offered when +.Em Tab +is pressed; +.Fl W +is similar but indicates the prompt is for a window. .Pp The following keys have a special meaning in the command prompt, depending on the value of the diff --git a/tmux.h b/tmux.h index c9c8637c..7d7e0e2d 100644 --- a/tmux.h +++ b/tmux.h @@ -1604,6 +1604,8 @@ struct client { #define PROMPT_INCREMENTAL 0x4 #define PROMPT_NOFORMAT 0x8 #define PROMPT_KEY 0x10 +#define PROMPT_WINDOW 0x20 +#define PROMPT_TARGET 0x40 int prompt_flags; struct session *session;