Add a -S flag to new-window to make it select the existing window if one
authornicm <nicm@openbsd.org>
Fri, 5 Feb 2021 12:23:49 +0000 (12:23 +0000)
committernicm <nicm@openbsd.org>
Fri, 5 Feb 2021 12:23:49 +0000 (12:23 +0000)
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@.

usr.bin/tmux/cmd-new-window.c
usr.bin/tmux/format.c
usr.bin/tmux/tmux.1

index a624cb7..d74ce0f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-new-window.c,v 1.89 2020/06/25 08:56:02 nicm Exp $ */
+/* $OpenBSD: cmd-new-window.c,v 1.90 2021/02/05 12:23:49 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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);
index c8ee1e9..d88a518 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: format.c,v 1.271 2021/01/29 09:48:43 nicm Exp $ */
+/* $OpenBSD: format.c,v 1.272 2021/02/05 12:23:49 nicm Exp $ */
 
 /*
  * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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);
index 7a3fc0a..831005b 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.816 2021/02/02 07:33:29 jmc Exp $
+.\" $OpenBSD: tmux.1,v 1.817 2021/02/05 12:23:49 nicm Exp $
 .\"
 .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
 .\"
@@ -14,7 +14,7 @@
 .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: February 2 2021 $
+.Dd $Mdocdate: February 5 2021 $
 .Dt TMUX 1
 .Os
 .Sh NAME
@@ -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