From be471c328ea0ae04026e4ff32fda7b7f11c74255 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 5 Feb 2021 12:23:49 +0000 Subject: [PATCH] Add a -S flag to new-window to make it select the existing window if one with the given name already exists rather than failing with an error. Also add a format to check if a window or session name exists which allows the same with other commands. Requested by and discussed with kn@. --- cmd-new-window.c | 38 ++++++++++++++++++++++++++---- format.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++- tmux.1 | 21 ++++++++++++++++- 3 files changed, 114 insertions(+), 6 deletions(-) diff --git a/cmd-new-window.c b/cmd-new-window.c index ca3e66c4..712e2a79 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -38,8 +38,8 @@ const struct cmd_entry cmd_new_window_entry = { .name = "new-window", .alias = "neww", - .args = { "abc:de:F:kn:Pt:", 0, -1 }, - .usage = "[-abdkP] [-c start-directory] [-e environment] [-F format] " + .args = { "abc:de:F:kn:PSt:", 0, -1 }, + .usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] " "[-n window-name] " CMD_TARGET_WINDOW_USAGE " [command]", .target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX }, @@ -52,6 +52,7 @@ static enum cmd_retval cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) { struct args *args = cmd_get_args(self); + struct client *c = cmdq_get_client(item); struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state *target = cmdq_get_target(item); struct spawn_context sc; @@ -59,12 +60,41 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) struct session *s = target->s; struct winlink *wl = target->wl; int idx = target->idx, before; - struct winlink *new_wl; + struct winlink *new_wl = NULL; char *cause = NULL, *cp; - const char *template, *add; + const char *template, *add, *name; struct cmd_find_state fs; struct args_value *value; + /* + * If -S and -n are given and -t is not and a single window with this + * name already exists, select it. + */ + name = args_get(args, 'n'); + if (args_has(args, 'S') && name != NULL && target->idx == -1) { + RB_FOREACH(wl, winlinks, &s->windows) { + if (strcmp(wl->window->name, name) != 0) + continue; + if (new_wl == NULL) { + new_wl = wl; + continue; + } + cmdq_error(item, "multiple windows named %s", name); + return (CMD_RETURN_ERROR); + } + if (new_wl != NULL) { + if (args_has(args, 'd')) + return (CMD_RETURN_NORMAL); + if (session_set_current(s, new_wl) == 0) + server_redraw_session(s); + if (c != NULL && c->session != NULL) + s->curw->window->latest = c; + recalculate_sizes(); + return (CMD_RETURN_NORMAL); + } + } + + before = args_has(args, 'b'); if (args_has(args, 'a') || before) { idx = winlink_shuffle_up(s, wl, before); diff --git a/format.c b/format.c index 25b80249..ecf299d1 100644 --- a/format.c +++ b/format.c @@ -100,6 +100,8 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2) #define FORMAT_LENGTH 0x800 #define FORMAT_WIDTH 0x1000 #define FORMAT_QUOTE_STYLE 0x2000 +#define FORMAT_WINDOW_NAME 0x4000 +#define FORMAT_SESSION_NAME 0x8000 /* Limit on recursion. */ #define FORMAT_LOOP_LIMIT 10 @@ -1733,7 +1735,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s, } /* Now try single character with arguments. */ - if (strchr("mCst=peq", cp[0]) == NULL) + if (strchr("mCNst=peq", cp[0]) == NULL) break; c = cp[0]; @@ -1857,6 +1859,24 @@ format_search(struct format_modifier *fm, struct window_pane *wp, const char *s) return (value); } +/* Does session name exist? */ +static char * +format_session_name(struct format_expand_state *es, const char *fmt) +{ + char *name; + struct session *s; + + name = format_expand1(es, fmt); + RB_FOREACH(s, sessions, &sessions) { + if (strcmp(s->name, name) == 0) { + free(name); + return (xstrdup("1")); + } + } + free(name); + return (xstrdup("0")); +} + /* Loop over sessions. */ static char * format_loop_sessions(struct format_expand_state *es, const char *fmt) @@ -1892,6 +1912,30 @@ format_loop_sessions(struct format_expand_state *es, const char *fmt) return (value); } +/* Does window name exist? */ +static char * +format_window_name(struct format_expand_state *es, const char *fmt) +{ + struct format_tree *ft = es->ft; + char *name; + struct winlink *wl; + + if (ft->s == NULL) { + format_log(es, "window name but no session"); + return (NULL); + } + + name = format_expand1(es, fmt); + RB_FOREACH(wl, winlinks, &ft->s->windows) { + if (strcmp(wl->window->name, name) == 0) { + free(name); + return (xstrdup("1")); + } + } + free(name); + return (xstrdup("0")); +} + /* Loop over windows. */ static char * format_loop_windows(struct format_expand_state *es, const char *fmt) @@ -2251,6 +2295,13 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, case 'T': modifiers |= FORMAT_EXPANDTIME; break; + case 'N': + if (fm->argc < 1 || + strchr(fm->argv[0], 'w') != NULL) + modifiers |= FORMAT_WINDOW_NAME; + else if (strchr(fm->argv[0], 's') != NULL) + modifiers |= FORMAT_SESSION_NAME; + break; case 'S': modifiers |= FORMAT_SESSIONS; break; @@ -2291,6 +2342,14 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, value = format_loop_panes(es, copy); if (value == NULL) goto fail; + } else if (modifiers & FORMAT_WINDOW_NAME) { + value = format_window_name(es, copy); + if (value == NULL) + goto fail; + } else if (modifiers & FORMAT_SESSION_NAME) { + value = format_session_name(es, copy); + if (value == NULL) + goto fail; } else if (search != NULL) { /* Search in pane. */ new = format_expand1(es, copy); diff --git a/tmux.1 b/tmux.1 index c076f0cb..530cd559 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2348,7 +2348,7 @@ the .Ic base-index option. .It Xo Ic new-window -.Op Fl abdkP +.Op Fl abdkPS .Op Fl c Ar start-directory .Op Fl e Ar environment .Op Fl F Ar format @@ -2377,6 +2377,14 @@ represents the window to be created; if the target already exists an error is shown, unless the .Fl k flag is used, in which case it is destroyed. +If +.Fl S +is given and a window named +.Ar window-name +already exists, it is selected (unless +.Fl d +is also given in which case the command does nothing). +.Pp .Ar shell-command is the command to execute. If @@ -4688,6 +4696,17 @@ For example, to get a list of windows formatted like the status line: #{W:#{E:window-status-format} ,#{E:window-status-current-format} } .Ed .Pp +.Ql N:\& +checks if a window (without any suffix or with the +.Ql w +suffix) or a session (with the +.Ql s +suffix) name exists, for example +.Ql `N/w:foo` +is replaced with 1 if a window named +.Ql foo +exists. +.Pp A prefix of the form .Ql s/foo/bar/:\& will substitute