The branch, master has been updated
       via  94a8ef1caef855d1a43b6373dd08ce0bbf4aadd5 (commit)
       via  95195f52584565483bf9850840f6d81cd88bf9b2 (commit)
       via  a70762c9b50e9d9249fa9a56233c0df4129c82fc (commit)
       via  5bd5c9c84e4bde3461a50f15e387c5e9fb78d7cb (commit)
       via  05e7fbd60fcd1f5c82049dc2f416e7dd42577cfd (commit)
       via  1d1208e335644ee10ebe47363b2ca8db45bf9142 (commit)
      from  72e9ebf2ece28c986050162bf4f401a6a7679f53 (commit)

- Log -----------------------------------------------------------------
commit 94a8ef1caef855d1a43b6373dd08ce0bbf4aadd5
Merge: 72e9ebf 95195f5
Author: Thomas Adam <tho...@xteddy.org>
Commit: Thomas Adam <tho...@xteddy.org>

    Merge branch 'obsd-master'
    
    Conflicts:
        Makefile
        tmux.1

 Makefile.am           |    1 +
 cfg.c                 |   18 +-
 cmd-choose-buffer.c   |    2 +-
 cmd-choose-client.c   |    2 +-
 cmd-choose-tree.c     |    2 +-
 cmd-display-message.c |    2 +-
 cmd-find-window.c     |    2 +-
 cmd-find.c            | 1114 +++++++++++++++++++++++++++++++++++++++++++++++++
 cmd-load-buffer.c     |    2 +-
 cmd-new-session.c     |    2 +-
 cmd-save-buffer.c     |    2 +-
 cmd-select-pane.c     |   24 +-
 cmd-split-window.c    |    6 +-
 cmd.c                 |  937 +-----------------------------------------
 key-bindings.c        |    4 +-
 tmux.1                |  182 +++++----
 tmux.h                |   25 +-
 window.c              |   92 +++--
 18 files changed, 1330 insertions(+), 1089 deletions(-)

diff --cc Makefile.am
index 63e20b1,0000000..693d5b8
mode 100644,000000..100644
--- a/Makefile.am
+++ b/Makefile.am
@@@ -1,264 -1,0 +1,265 @@@
 +# $Id$
 +
 +# Obvious program stuff.
 +bin_PROGRAMS = tmux
 +CLEANFILES = tmux.1.mdoc tmux.1.man
 +
 +# Distribution tarball options.
 +EXTRA_DIST = \
 +      CHANGES FAQ README TODO COPYING examples compat \
 +      array.h compat.h tmux.h osdep-*.c mdoc2man.awk tmux.1
 +dist-hook:
 +      make clean
 +      grep "^#found_debug=" configure
 +      find $(distdir) -name .svn -type d|xargs rm -Rf
 +
 +# Preprocessor flags.
 +CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\""
 +
 +# glibc as usual does things ass-backwards and hides useful things by default,
 +# so everyone has to add this.
 +if IS_GLIBC
 +CFLAGS += -D_GNU_SOURCE
 +endif
 +
 +# Set flags for gcc. gcc4 whines abouts silly stuff so it needs slightly
 +# different flags.
 +if IS_GCC
 +CFLAGS += -std=gnu99 -O2
 +if IS_DEBUG
 +CFLAGS += -g
 +CFLAGS += -Wno-long-long -Wall -W -Wnested-externs -Wformat=2
 +CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
 +CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
 +CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
 +CFLAGS += -Wdeclaration-after-statement
 +CPPFLAGS += -DDEBUG
 +endif
 +if IS_GCC4
 +CPPFLAGS += -iquote.
 +if IS_DEBUG
 +CFLAGS += -Wno-pointer-sign
 +endif
 +else
 +CPPFLAGS += -I. -I-
 +endif
 +endif
 +
 +# Set flags for Solaris.
 +if IS_SUNOS
 +if IS_GCC
 +CPPFLAGS += -D_XPG6 -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS
 +else
 +CPPFLAGS += -D_XPG4_2 -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS
 +endif
 +endif
 +
 +# Set flags for Sun CC.
 +if IS_SUNCC
 +CFLAGS += -erroff=E_EMPTY_DECLARATION
 +endif
 +
 +# List of sources.
 +dist_tmux_SOURCES = \
 +      arguments.c \
 +      attributes.c \
 +      cfg.c \
 +      client.c \
 +      cmd-attach-session.c \
 +      cmd-bind-key.c \
 +      cmd-break-pane.c \
 +      cmd-capture-pane.c \
 +      cmd-choose-buffer.c \
 +      cmd-choose-client.c \
 +      cmd-choose-tree.c \
 +      cmd-clear-history.c \
 +      cmd-command-prompt.c \
 +      cmd-confirm-before.c \
 +      cmd-copy-mode.c \
 +      cmd-delete-buffer.c \
 +      cmd-detach-client.c \
 +      cmd-display-message.c \
 +      cmd-display-panes.c \
++      cmd-find.c \
 +      cmd-find-window.c \
 +      cmd-if-shell.c \
 +      cmd-join-pane.c \
 +      cmd-kill-pane.c \
 +      cmd-kill-server.c \
 +      cmd-kill-session.c \
 +      cmd-kill-window.c \
 +      cmd-list-buffers.c \
 +      cmd-list-clients.c \
 +      cmd-list-keys.c \
 +      cmd-list-panes.c \
 +      cmd-list-sessions.c \
 +      cmd-list-windows.c \
 +      cmd-list.c \
 +      cmd-load-buffer.c \
 +      cmd-lock-server.c \
 +      cmd-move-window.c \
 +      cmd-new-session.c \
 +      cmd-new-window.c \
 +      cmd-paste-buffer.c \
 +      cmd-pipe-pane.c \
 +      cmd-queue.c \
 +      cmd-refresh-client.c \
 +      cmd-rename-session.c \
 +      cmd-rename-window.c \
 +      cmd-resize-pane.c \
 +      cmd-respawn-pane.c \
 +      cmd-respawn-window.c \
 +      cmd-rotate-window.c \
 +      cmd-run-shell.c \
 +      cmd-save-buffer.c \
 +      cmd-select-layout.c \
 +      cmd-select-pane.c \
 +      cmd-select-window.c \
 +      cmd-send-keys.c \
 +      cmd-set-buffer.c \
 +      cmd-set-environment.c \
 +      cmd-set-option.c \
 +      cmd-show-environment.c \
 +      cmd-show-messages.c \
 +      cmd-show-options.c \
 +      cmd-source-file.c \
 +      cmd-split-window.c \
 +      cmd-string.c \
 +      cmd-swap-pane.c \
 +      cmd-swap-window.c \
 +      cmd-switch-client.c \
 +      cmd-unbind-key.c \
 +      cmd-wait-for.c \
 +      cmd.c \
 +      colour.c \
 +      control.c \
 +      control-notify.c \
 +      environ.c \
 +      format.c \
 +      grid-cell.c \
 +      grid-view.c \
 +      grid.c \
 +      input-keys.c \
 +      input.c \
 +      job.c \
 +      key-bindings.c \
 +      key-string.c \
 +      layout-custom.c \
 +      layout-set.c \
 +      layout.c \
 +      log.c \
 +      mode-key.c \
 +      names.c \
 +      notify.c \
 +      options-table.c \
 +      options.c \
 +      paste.c \
 +      resize.c \
 +      screen-redraw.c \
 +      screen-write.c \
 +      screen.c \
 +      server-client.c \
 +      server-fn.c \
 +      server-window.c \
 +      server.c \
 +      session.c \
 +      signal.c \
 +      status.c \
 +      style.c \
 +      tmux.c \
 +      tty-acs.c \
 +      tty-keys.c \
 +      tty-term.c \
 +      tty.c \
 +      utf8.c \
 +      window-choose.c \
 +      window-clock.c \
 +      window-copy.c \
 +      window.c \
 +      xmalloc.c \
 +      xterm-keys.c
 +nodist_tmux_SOURCES = osdep-@PLATFORM@.c
 +
 +# Pile in all the compat/ stuff that is needed.
 +if NO_FORKPTY
 +nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c
 +endif
 +if NO_IMSG
 +nodist_tmux_SOURCES += compat/imsg.c compat/imsg-buffer.c
 +endif
 +if NO_CLOSEFROM
 +nodist_tmux_SOURCES += compat/closefrom.c
 +endif
 +if NO_DAEMON
 +nodist_tmux_SOURCES += compat/daemon.c
 +endif
 +if NO_SETENV
 +nodist_tmux_SOURCES += compat/setenv.c
 +endif
 +if NO_STRLCAT
 +nodist_tmux_SOURCES += compat/strlcat.c
 +endif
 +if NO_STRLCPY
 +nodist_tmux_SOURCES += compat/strlcpy.c
 +endif
 +if NO_ASPRINTF
 +nodist_tmux_SOURCES += compat/asprintf.c
 +endif
 +if NO_FGETLN
 +nodist_tmux_SOURCES += compat/fgetln.c
 +endif
 +if NO_FPARSELN
 +nodist_tmux_SOURCES += compat/fparseln.c
 +endif
 +if NO_GETOPT
 +nodist_tmux_SOURCES += compat/getopt.c
 +endif
 +if NO_STRCASESTR
 +nodist_tmux_SOURCES += compat/strcasestr.c
 +endif
 +if NO_STRSEP
 +nodist_tmux_SOURCES += compat/strsep.c
 +endif
 +if NO_VIS
 +nodist_tmux_SOURCES += compat/vis.c compat/unvis.c
 +endif
 +if NO_STRTONUM
 +nodist_tmux_SOURCES += compat/strtonum.c
 +endif
 +if NO_B64_NTOP
 +nodist_tmux_SOURCES += compat/b64_ntop.c
 +endif
 +if NO_CFMAKERAW
 +nodist_tmux_SOURCES += compat/cfmakeraw.c
 +endif
 +if NO_OPENAT
 +nodist_tmux_SOURCES += compat/openat.c
 +endif
 +
 +# Install tmux.1 in the right format.
 +install-exec-hook:
 +      if test x@MANFORMAT@ = xmdoc; then \
 +              sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1 \
 +                      >$(srcdir)/tmux.1.mdoc; \
 +      else \
 +              sed -e "s|@SYSCONFDIR@|$(sysconfdir)|g" $(srcdir)/tmux.1| \
 +                      $(AWK) -f$(srcdir)/mdoc2man.awk >$(srcdir)/tmux.1.man; \
 +      fi
 +      $(mkdir_p) $(DESTDIR)$(mandir)/man1
 +      $(INSTALL_DATA) $(srcdir)/tmux.1.@MANFORMAT@ \
 +              $(DESTDIR)$(mandir)/man1/tmux.1
 +
 +# Update SF web site.
 +upload-index.html: update-index.html
 +      scp www/index.html www/main.css www/images/*.png \
 +              ${USER},t...@web.sf.net:/home/groups/t/tm/tmux/htdocs
 +      rm -f www/index.html www/images/small-*
 +
 +update-index.html:
 +      (cd www/images && \
 +              rm -f small-* && \
 +              for i in *.png; do \
 +                      convert "$$i" -resize 200x150 "small-$$i"; \
 +              done \
 +      )
 +      sed "s/%%RELEASE%%/${RELEASE}/g" www/index.html.in >www/index.html
diff --cc tmux.1
index d9011c4,cd7ec39..10ba6f9
--- a/tmux.1
+++ b/tmux.1
@@@ -362,9 -358,10 +362,10 @@@ argument with one o
  or
  .Ar target-pane .
  These specify the client, session, window or pane which a command should 
affect.
+ .Pp
  .Ar target-client
 -should be the name of the
 -.Xr pty 4
 +is the name of the
 +.Xr pty 7
  file to which the client is connected, for example either of
  .Pa /dev/ttyp1
  or


commit 95195f52584565483bf9850840f6d81cd88bf9b2
Author: nicm <nicm>
Commit: nicm <nicm>

    Rewrite of the target resolution internals to be simpler and more
    consistent but with much less duplication, but keeping the same internal
    API. Also adds more readable aliases for some of the special tokens used
    in targets (eg "{start}" instead of "^"). Some behaviours may have
    changed, for example prefix matches now happen before fnmatch.
---
 Makefile              |    1 +
 cmd-choose-buffer.c   |    2 +-
 cmd-choose-client.c   |    2 +-
 cmd-choose-tree.c     |    2 +-
 cmd-display-message.c |    2 +-
 cmd-find-window.c     |    2 +-
 cmd-find.c            | 1114 +++++++++++++++++++++++++++++++++++++++++++++++++
 cmd-load-buffer.c     |    2 +-
 cmd-new-session.c     |    2 +-
 cmd-save-buffer.c     |    2 +-
 cmd.c                 |  937 +-----------------------------------------
 tmux.1                |  184 +++++----
 tmux.h                |   25 +-
 13 files changed, 1250 insertions(+), 1027 deletions(-)

diff --git a/Makefile b/Makefile
index a719eaf..ac7e6e5 100644
--- a/Makefile
+++ b/Makefile
@@ -69,6 +69,7 @@ SRCS= arguments.c \
        cmd-unbind-key.c \
        cmd-wait-for.c \
        cmd.c \
+       cmd-find.c \
        cmd-queue.c \
        colour.c \
        control.c \
diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c
index 33125a0..af17897 100644
--- a/cmd-choose-buffer.c
+++ b/cmd-choose-buffer.c
@@ -53,7 +53,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
        u_int                            idx;
        int                              utf8flag;
 
-       if ((c = cmd_current_client(cmdq)) == NULL) {
+       if ((c = cmd_find_client(cmdq, NULL, 1)) == NULL) {
                cmdq_error(cmdq, "no client available");
                return (CMD_RETURN_ERROR);
        }
diff --git a/cmd-choose-client.c b/cmd-choose-client.c
index 49fe2a3..93ac28a 100644
--- a/cmd-choose-client.c
+++ b/cmd-choose-client.c
@@ -61,7 +61,7 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_q *cmdq)
        char                            *action;
        u_int                            idx, cur;
 
-       if ((c = cmd_current_client(cmdq)) == NULL) {
+       if ((c = cmd_find_client(cmdq, NULL, 1)) == NULL) {
                cmdq_error(cmdq, "no client available");
                return (CMD_RETURN_ERROR);
        }
diff --git a/cmd-choose-tree.c b/cmd-choose-tree.c
index 823d042..0b0fea6 100644
--- a/cmd-choose-tree.c
+++ b/cmd-choose-tree.c
@@ -87,7 +87,7 @@ cmd_choose_tree_exec(struct cmd *self, struct cmd_q *cmdq)
        ses_template = win_template = NULL;
        ses_action = win_action = NULL;
 
-       if ((c = cmd_current_client(cmdq)) == NULL) {
+       if ((c = cmd_find_client(cmdq, NULL, 1)) == NULL) {
                cmdq_error(cmdq, "no client available");
                return (CMD_RETURN_ERROR);
        }
diff --git a/cmd-display-message.c b/cmd-display-message.c
index 0a61fd1..ee9eafe 100644
--- a/cmd-display-message.c
+++ b/cmd-display-message.c
@@ -78,7 +78,7 @@ cmd_display_message_exec(struct cmd *self, struct cmd_q *cmdq)
                if (c == NULL)
                        return (CMD_RETURN_ERROR);
        } else {
-               c = cmd_current_client(cmdq);
+               c = cmd_find_client(cmdq, NULL, 1);
                if (c == NULL && !args_has(self->args, 'p')) {
                        cmdq_error(cmdq, "no client available");
                        return (CMD_RETURN_ERROR);
diff --git a/cmd-find-window.c b/cmd-find-window.c
index 25155f7..64e092b 100644
--- a/cmd-find-window.c
+++ b/cmd-find-window.c
@@ -143,7 +143,7 @@ cmd_find_window_exec(struct cmd *self, struct cmd_q *cmdq)
        const char                      *template;
        u_int                            i, match_flags;
 
-       if ((c = cmd_current_client(cmdq)) == NULL) {
+       if ((c = cmd_find_client(cmdq, NULL, 1)) == NULL) {
                cmdq_error(cmdq, "no client available");
                return (CMD_RETURN_ERROR);
        }
diff --git a/cmd-find.c b/cmd-find.c
new file mode 100644
index 0000000..a71968a
--- /dev/null
+++ b/cmd-find.c
@@ -0,0 +1,1114 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2015 Nicholas Marriott <n...@users.sourceforge.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <fnmatch.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+
+#include "tmux.h"
+
+#define CMD_FIND_PREFER_UNATTACHED 0x1
+#define CMD_FIND_QUIET 0x2
+#define CMD_FIND_WINDOW_INDEX 0x4
+
+enum cmd_find_type {
+       CMD_FIND_PANE,
+       CMD_FIND_WINDOW,
+       CMD_FIND_SESSION,
+};
+
+struct cmd_find_state {
+       struct cmd_q            *cmdq;
+       int                      flags;
+       struct cmd_find_state   *current;
+
+       struct session          *s;
+       struct winlink          *wl;
+       struct window           *w;
+       struct window_pane      *wp;
+       int                      idx;
+};
+
+int             cmd_find_client_better(struct client *, struct client *);
+struct client  *cmd_find_best_client(struct client **, u_int);
+int             cmd_find_session_better(struct session *, struct session *,
+                    int);
+struct session *cmd_find_best_session(struct session **, u_int, int);
+int             cmd_find_best_session_with_window(struct cmd_find_state *);
+int             cmd_find_best_winlink_with_window(struct cmd_find_state *);
+
+int             cmd_find_current_session_with_client(struct cmd_find_state *);
+int             cmd_find_current_session(struct cmd_find_state *);
+struct client  *cmd_find_current_client(struct cmd_q *);
+
+const char     *cmd_find_map_table(const char *[][2], const char *);
+
+int    cmd_find_get_session(struct cmd_find_state *, const char *);
+int    cmd_find_get_window(struct cmd_find_state *, const char *);
+int    cmd_find_get_window_with_session(struct cmd_find_state *, const char *);
+int    cmd_find_get_window_with_pane(struct cmd_find_state *);
+int    cmd_find_get_pane(struct cmd_find_state *, const char *);
+int    cmd_find_get_pane_with_session(struct cmd_find_state *, const char *);
+int    cmd_find_get_pane_with_window(struct cmd_find_state *, const char *);
+
+void   cmd_find_clear_state(struct cmd_find_state *, struct cmd_q *, int);
+void   cmd_find_log_state(const char *, const char *, struct cmd_find_state *);
+
+struct cmd_find_state  *cmd_find_target(struct cmd_q *, const char *,
+           enum cmd_find_type, int);
+
+const char *cmd_find_session_table[][2] = {
+       { NULL, NULL }
+};
+const char *cmd_find_window_table[][2] = {
+       { "{start}", "^" },
+       { "{last}", "!" },
+       { "{end}", "$" },
+       { "{next}", "+" },
+       { "{previous}", "-" },
+       { NULL, NULL }
+};
+const char *cmd_find_pane_table[][2] = {
+       { "{last}", "!" },
+       { "{next}", "+" },
+       { "{previous}", "-" },
+       { "{top}", "top" },
+       { "{bottom}", "bottom" },
+       { "{left}", "left" },
+       { "{right}", "right" },
+       { "{top-left}", "top-left" },
+       { "{top-right}", "top-right" },
+       { "{bottom-left}", "bottom-left" },
+       { "{bottom-right}", "bottom-right" },
+       { "{up}", "{up}" },
+       { "{down}", "{down}" },
+       { "{left}", "{left}" },
+       { "{right}", "{right}" },
+       { NULL, NULL }
+};
+
+/* Is this client better? */
+int
+cmd_find_client_better(struct client *c, struct client *than)
+{
+       if (than == NULL)
+               return (1);
+       return (timercmp(&c->activity_time, &than->activity_time, >));
+}
+
+/* Find best client from a list, or all if list is NULL. */
+struct client *
+cmd_find_best_client(struct client **clist, u_int csize)
+{
+       struct client   *c_loop, *c;
+       u_int            i;
+
+       c = NULL;
+       if (clist != NULL) {
+               for (i = 0; i < csize; i++) {
+                       if (cmd_find_client_better(clist[i], c))
+                               c = clist[i];
+               }
+       } else {
+               TAILQ_FOREACH(c_loop, &clients, entry) {
+                       if (cmd_find_client_better(c_loop, c))
+                               c_loop = c;
+               }
+       }
+       return (c);
+}
+
+/* Is this session better? */
+int
+cmd_find_session_better(struct session *s, struct session *than, int flags)
+{
+       int     attached;
+
+       if (than == NULL)
+               return (1);
+       if (flags & CMD_FIND_PREFER_UNATTACHED) {
+               attached = (~than->flags & SESSION_UNATTACHED);
+               if (attached && (s->flags & SESSION_UNATTACHED))
+                       return (1);
+               else if (!attached && (~s->flags & SESSION_UNATTACHED))
+                       return (0);
+       }
+       return (timercmp(&s->activity_time, &than->activity_time, >));
+}
+
+/* Find best session from a list, or all if list is NULL. */
+struct session *
+cmd_find_best_session(struct session **slist, u_int ssize, int flags)
+{
+       struct session   *s_loop, *s;
+       u_int             i;
+
+       s = NULL;
+       if (slist != NULL) {
+               for (i = 0; i < ssize; i++) {
+                       if (cmd_find_session_better(slist[i], s, flags))
+                               s = slist[i];
+               }
+       } else {
+               RB_FOREACH(s_loop, sessions, &sessions) {
+                       if (cmd_find_session_better(s_loop, s, flags))
+                               s = s_loop;
+               }
+       }
+       return (s);
+}
+
+/* Find best session and winlink for window. */
+int
+cmd_find_best_session_with_window(struct cmd_find_state *fs)
+{
+       struct session  **slist = NULL;
+       u_int             ssize;
+       struct session   *s;
+
+       ssize = 0;
+       RB_FOREACH(s, sessions, &sessions) {
+               if (!session_has(s, fs->w))
+                       continue;
+               slist = xreallocarray (slist, ssize + 1, sizeof *slist);
+               slist[ssize++] = s;
+       }
+       if (ssize == 0)
+               goto fail;
+       fs->s = cmd_find_best_session(slist, ssize, fs->flags);
+       if (fs->s == NULL)
+               goto fail;
+       free (slist);
+       return (cmd_find_best_winlink_with_window(fs));
+
+fail:
+       free(slist);
+       return (-1);
+}
+
+/*
+ * Find the best winlink for a window (the current if it contains the pane,
+ * otherwise the first).
+ */
+int
+cmd_find_best_winlink_with_window(struct cmd_find_state *fs)
+{
+       struct winlink   *wl, *wl_loop;
+
+       wl = NULL;
+       if (fs->s->curw->window == fs->w)
+               wl = fs->s->curw;
+       else {
+               RB_FOREACH(wl_loop, winlinks, &fs->s->windows) {
+                       if (wl_loop->window == fs->w) {
+                               wl = wl_loop;
+                               break;
+                       }
+               }
+       }
+       if (wl == NULL)
+               return (-1);
+       fs->wl = wl;
+       fs->idx = fs->wl->idx;
+       return (0);
+}
+
+/* Find current session when we have an unattached client. */
+int
+cmd_find_current_session_with_client(struct cmd_find_state *fs)
+{
+       struct window_pane      *wp;
+
+       /* If this is running in a pane, that's great. */
+       RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
+               if (strcmp(wp->tty, fs->cmdq->client->tty.path) == 0)
+                       break;
+       }
+
+       /* Not running in a pane. We know nothing. Find the best session. */
+       if (wp == NULL) {
+               fs->s = cmd_find_best_session(NULL, 0, fs->flags);
+               if (fs->s == NULL)
+                       return (-1);
+               fs->wl = fs->s->curw;
+               fs->idx = fs->wl->idx;
+               fs->w = fs->wl->window;
+               fs->wp = fs->w->active;
+               return (0);
+       }
+
+       /* We now know the window and pane. */
+       fs->w = wp->window;
+       fs->wp = wp;
+
+       /* Find the best session and winlink. */
+       if (cmd_find_best_session_with_window(fs) != 0)
+               return (-1);
+       return (0);
+}
+
+/*
+ * Work out the best current state. If this function succeeds, the state is
+ * guaranteed to be completely filled in.
+ */
+int
+cmd_find_current_session(struct cmd_find_state *fs)
+{
+       /* If we know the current client, use it. */
+       if (fs->cmdq->client != NULL) {
+               if (fs->cmdq->client->session == NULL)
+                       return (cmd_find_current_session_with_client(fs));
+               fs->s = fs->cmdq->client->session;
+               fs->wl = fs->s->curw;
+               fs->idx = fs->wl->idx;
+               fs->w = fs->wl->window;
+               fs->wp = fs->w->active;
+               return (0);
+       }
+
+       /* We know nothing, find the best session and client. */
+       fs->s = cmd_find_best_session(NULL, 0, fs->flags);
+       if (fs->s == NULL)
+               return (-1);
+       fs->wl = fs->s->curw;
+       fs->idx = fs->wl->idx;
+       fs->w = fs->wl->window;
+       fs->wp = fs->w->active;
+
+       return (0);
+}
+
+/* Work out the best current client. */
+struct client *
+cmd_find_current_client(struct cmd_q *cmdq)
+{
+       struct cmd_find_state    current;
+       struct session          *s;
+       struct client           *c, **clist = NULL;
+       u_int                    csize;
+
+       /* If the queue client has a session, use it. */
+       if (cmdq->client != NULL && cmdq->client->session != NULL)
+               return (cmdq->client);
+
+       /* Otherwise find the current session. */
+       cmd_find_clear_state(&current, cmdq, 0);
+       if (cmd_find_current_session(&current) != 0)
+               return (NULL);
+
+       /* If it is attached, find the best of it's clients. */
+       s = current.s;
+       if (~s->flags & SESSION_UNATTACHED) {
+               csize = 0;
+               TAILQ_FOREACH(c, &clients, entry) {
+                       if (c->session != s)
+                               continue;
+                       clist = xreallocarray (clist, csize + 1, sizeof *clist);
+                       clist[csize++] = c;
+               }
+               if (csize != 0) {
+                       c = cmd_find_best_client(clist, csize);
+                       if (c != NULL) {
+                               free(clist);
+                               return (c);
+                       }
+               }
+               free(clist);
+       }
+
+       /* Otherwise pick best of all clients. */
+       return (cmd_find_best_client(NULL, 0));
+}
+
+/* Maps string in table. */
+const char *
+cmd_find_map_table(const char *table[][2], const char *s)
+{
+       u_int   i;
+
+       for (i = 0; table[i][0] != NULL; i++) {
+               if (strcmp(s, table[i][0]) == 0)
+                       return (table[i][1]);
+       }
+       return (s);
+}
+
+/* Find session from string. Fills in s. */
+int
+cmd_find_get_session(struct cmd_find_state *fs, const char *session)
+{
+       struct session  *s, *s_loop;
+
+       log_debug("%s: %s", __func__, session);
+
+       /* Check for session ids starting with $. */
+       if (*session == '$') {
+               fs->s = session_find_by_id_str(session);
+               if (fs->s == NULL)
+                       return (-1);
+               return (0);
+       }
+
+       /* Look for exactly this session. */
+       fs->s = session_find(session);
+       if (fs->s != NULL)
+               return (0);
+
+       /* Otherwise look for prefix. */
+       s = NULL;
+       RB_FOREACH(s_loop, sessions, &sessions) {
+               if (strncmp(session, s_loop->name, strlen(session)) == 0) {
+                       if (s != NULL)
+                               return (-1);
+                       s = s_loop;
+               }
+       }
+       if (s != NULL) {
+               fs->s = s;
+               return (0);
+       }
+
+       /* Then as a pattern. */
+       s = NULL;
+       RB_FOREACH(s_loop, sessions, &sessions) {
+               if (fnmatch(session, s_loop->name, 0) == 0) {
+                       if (s != NULL)
+                               return (-1);
+                       s = s_loop;
+               }
+       }
+       if (s != NULL) {
+               fs->s = s;
+               return (0);
+       }
+
+       return (-1);
+}
+
+/* Find window from string. Fills in s, wl, w. */
+int
+cmd_find_get_window(struct cmd_find_state *fs, const char *window)
+{
+       log_debug("%s: %s", __func__, window);
+
+       /* Check for window ids starting with @. */
+       if (*window == '@') {
+               fs->w = window_find_by_id_str(window);
+               if (fs->w == NULL)
+                       return (-1);
+               return (cmd_find_best_session_with_window(fs));
+       }
+
+       /* Not a window id, so use the current session. */
+       fs->s = fs->current->s;
+
+       /* We now only need to find the winlink in this session. */
+       return (cmd_find_get_window_with_session(fs, window));
+}
+
+/*
+ * Find window from string, assuming it is in given session. Needs s, fills in
+ * wl and w.
+ */
+int
+cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window)
+{
+       struct winlink  *wl;
+       const char      *errstr;
+       int              idx, n;
+       struct session  *s;
+
+       log_debug("%s: %s", __func__, window);
+
+       /* Check for window ids starting with @. */
+       if (*window == '@') {
+               fs->w = window_find_by_id_str(window);
+               if (fs->w == NULL || !session_has(fs->s, fs->w))
+                       return (-1);
+               return (cmd_find_best_winlink_with_window(fs));
+       }
+
+       /* Try as an offset. */
+       if (window[0] == '+' || window[0] == '-') {
+               if (window[1] != '\0')
+                       n = strtonum(window + 1, 1, INT_MAX, NULL);
+               else
+                       n = 1;
+               s = fs->s;
+               if (fs->flags & CMD_FIND_WINDOW_INDEX) {
+                       if (window[0] == '+') {
+                               if (INT_MAX - s->curw->idx < n)
+                                       return (-1);
+                               fs->idx = s->curw->idx + n;
+                       } else {
+                               if (n < s->curw->idx)
+                                       return (-1);
+                               fs->idx = s->curw->idx - n;
+                       }
+                       return (0);
+               }
+               if (window[0] == '+')
+                       fs->wl = winlink_next_by_number(s->curw, s, n);
+               else
+                       fs->wl = winlink_previous_by_number(s->curw, s, n);
+               if (fs->wl != NULL) {
+                       fs->idx = fs->wl->idx;
+                       fs->w = fs->wl->window;
+                       return (0);
+               }
+       }
+
+       /* Try special characters. */
+       if (strcmp(window, "!") == 0) {
+               fs->wl = TAILQ_FIRST(&fs->s->lastw);
+               if (fs->wl == NULL)
+                       return (-1);
+               fs->idx = fs->wl->idx;
+               fs->w = fs->wl->window;
+               return (0);
+       } else if (strcmp(window, "^") == 0) {
+               fs->wl = RB_MIN(winlinks, &fs->s->windows);
+               if (fs->wl == NULL)
+                       return (-1);
+               fs->idx = fs->wl->idx;
+               fs->w = fs->wl->window;
+               return (0);
+       } else if (strcmp(window, "$") == 0) {
+               fs->wl = RB_MAX(winlinks, &fs->s->windows);
+               if (fs->wl == NULL)
+                       return (-1);
+               fs->idx = fs->wl->idx;
+               fs->w = fs->wl->window;
+               return (0);
+       }
+
+       /* First see if this is a valid window index in this session. */
+       idx = strtonum(window, 0, INT_MAX, &errstr);
+       if (errstr == NULL) {
+               if (fs->flags & CMD_FIND_WINDOW_INDEX) {
+                       fs->idx = idx;
+                       return (0);
+               }
+               fs->wl = winlink_find_by_index(&fs->s->windows, idx);
+               if (fs->wl != NULL) {
+                       fs->w = fs->wl->window;
+                       return (0);
+               }
+       }
+
+       /* Look for exact matches, error if more than one. */
+       fs->wl = NULL;
+       RB_FOREACH(wl, winlinks, &fs->s->windows) {
+               if (strcmp(window, wl->window->name) == 0) {
+                       if (fs->wl != NULL)
+                               return (-1);
+                       fs->wl = wl;
+               }
+       }
+       if (fs->wl != NULL) {
+               fs->idx = fs->wl->idx;
+               fs->w = fs->wl->window;
+               return (0);
+       }
+
+       /* Try as the start of a window name, error if multiple. */
+       fs->wl = NULL;
+       RB_FOREACH(wl, winlinks, &fs->s->windows) {
+               if (strncmp(window, wl->window->name, strlen(window)) == 0) {
+                       if (fs->wl != NULL)
+                               return (-1);
+                       fs->wl = wl;
+               }
+       }
+       if (fs->wl != NULL) {
+               fs->idx = fs->wl->idx;
+               fs->w = fs->wl->window;
+               return (0);
+       }
+
+       /* Now look for pattern matches, again error if multiple. */
+       fs->wl = NULL;
+       RB_FOREACH(wl, winlinks, &fs->s->windows) {
+               if (fnmatch(window, wl->window->name, 0) == 0) {
+                       if (fs->wl != NULL)
+                               return (-1);
+                       fs->wl = wl;
+               }
+       }
+       if (fs->wl != NULL) {
+               fs->idx = fs->wl->idx;
+               fs->w = fs->wl->window;
+               return (0);
+       }
+
+       return (-1);
+}
+
+/* Find window from given pane. Needs wp, fills in s and wl and w. */
+int
+cmd_find_get_window_with_pane(struct cmd_find_state *fs)
+{
+       log_debug("%s", __func__);
+
+       fs->w = fs->wp->window;
+       return (cmd_find_best_session_with_window(fs));
+}
+
+/* Find pane from string. Fills in s, wl, w, wp. */
+int
+cmd_find_get_pane(struct cmd_find_state *fs, const char *pane)
+{
+       log_debug("%s: %s", __func__, pane);
+
+       /* Check for pane ids starting with %. */
+       if (*pane == '%') {
+               fs->wp = window_pane_find_by_id_str(pane);
+               if (fs->wp == NULL)
+                       return (-1);
+               fs->w = fs->wp->window;
+               return (cmd_find_best_session_with_window(fs));
+       }
+
+       /* Not a pane id, so use the current session and window. */
+       fs->s = fs->current->s;
+       fs->wl = fs->current->wl;
+       fs->idx = fs->current->idx;
+       fs->w = fs->current->w;
+
+       /* We now only need to find the pane in this window. */
+       return (cmd_find_get_pane_with_window(fs, pane));
+}
+
+/*
+ * Find pane from string, assuming it is in given session. Needs s, fills in wl
+ * and w and wp.
+ */
+int
+cmd_find_get_pane_with_session(struct cmd_find_state *fs, const char *pane)
+{
+       log_debug("%s: %s", __func__, pane);
+
+       /* Check for pane ids starting with %. */
+       if (*pane == '%') {
+               fs->wp = window_pane_find_by_id_str(pane);
+               if (fs->wp == NULL)
+                       return (-1);
+               fs->w = fs->wp->window;
+               return (cmd_find_best_winlink_with_window(fs));
+       }
+
+       /* Otherwise use the current window. */
+       fs->wl = fs->s->curw;
+       fs->idx = fs->wl->idx;
+       fs->w = fs->wl->window;
+
+       /* Now we just need to look up the pane. */
+       return (cmd_find_get_pane_with_window(fs, pane));
+}
+
+/*
+ * Find pane from string, assuming it is in the given window. Needs w, fills in
+ * wp.
+ */
+int
+cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
+{
+       const char              *errstr;
+       int                      idx;
+       struct window_pane      *wp;
+       u_int                    n;
+
+       log_debug("%s: %s", __func__, pane);
+
+       /* Check for pane ids starting with %. */
+       if (*pane == '%') {
+               fs->wp = window_pane_find_by_id_str(pane);
+               if (fs->wp == NULL || fs->wp->window != fs->w)
+                       return (-1);
+               return (0);
+       }
+
+       /* Try special characters. */
+       if (strcmp(pane, "!") == 0) {
+               if (fs->w->last == NULL)
+                       return (-1);
+               fs->wp = fs->w->last;
+               return (0);
+       } else if (strcmp(pane, "{up}") == 0) {
+               fs->wp = window_pane_find_up(fs->w->active);
+               if (fs->wp == NULL)
+                       return (-1);
+               return (0);
+       } else if (strcmp(pane, "{down}") == 0) {
+               fs->wp = window_pane_find_down(fs->w->active);
+               if (fs->wp == NULL)
+                       return (-1);
+               return (0);
+       } else if (strcmp(pane, "{left}") == 0) {
+               fs->wp = window_pane_find_left(fs->w->active);
+               if (fs->wp == NULL)
+                       return (-1);
+               return (0);
+       } else if (strcmp(pane, "{right}") == 0) {
+               fs->wp = window_pane_find_right(fs->w->active);
+               if (fs->wp == NULL)
+                       return (-1);
+               return (0);
+       }
+
+       /* Try as an offset. */
+       if (pane[0] == '+' || pane[0] == '-') {
+               if (pane[1] != '\0')
+                       n = strtonum(pane + 1, 1, INT_MAX, NULL);
+               else
+                       n = 1;
+               wp = fs->w->active;
+               if (pane[0] == '+')
+                       fs->wp = window_pane_next_by_number(fs->w, wp, n);
+               else
+                       fs->wp = window_pane_previous_by_number(fs->w, wp, n);
+               if (fs->wp != NULL)
+                       return (0);
+       }
+
+       /* Get pane by index. */
+       idx = strtonum(pane, 0, INT_MAX, &errstr);
+       if (errstr == NULL) {
+               fs->wp = window_pane_at_index(fs->w, idx);
+               if (fs->wp != NULL)
+                       return (0);
+       }
+
+       /* Try as a description. */
+       fs->wp = window_find_string(fs->w, pane);
+       if (fs->wp != NULL)
+               return (0);
+
+       return (-1);
+}
+
+/* Clear state. */
+void
+cmd_find_clear_state(struct cmd_find_state *fs, struct cmd_q *cmdq, int flags)
+{
+       memset (fs, 0, sizeof *fs);
+
+       fs->cmdq = cmdq;
+       fs->flags = flags;
+
+       fs->idx = -1;
+}
+
+/* Split target into pieces and resolve for the given type. */
+struct cmd_find_state *
+cmd_find_target(struct cmd_q *cmdq, const char *target, enum cmd_find_type 
type,
+    int flags)
+{
+       static struct cmd_find_state     fs, current;
+       struct mouse_event              *m;
+       char                            *colon, *period, *copy = NULL;
+       const char                      *session, *window, *pane;
+
+       /* Find current state. */
+       cmd_find_clear_state(&current, cmdq, flags);
+       if (cmd_find_current_session(&current) != 0) {
+               if (~flags & CMD_FIND_QUIET)
+                       cmdq_error(cmdq, "no current session");
+               goto error;
+       }
+
+       /* Clear new state. */
+       cmd_find_clear_state(&fs, cmdq, flags);
+       fs.current = &current;
+
+       /* An empty or NULL target is the current. */
+       if (target == NULL || *target == '\0')
+               goto current;
+
+       /* Mouse target is a plain = or {mouse}. */
+       if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
+               m = &cmdq->item->mouse;
+               switch (type) {
+               case CMD_FIND_PANE:
+                       fs.wp = cmd_mouse_pane(m, &fs.s, &fs.wl);
+                       if (fs.wp != NULL)
+                               fs.w = fs.wl->window;
+                       break;
+               case CMD_FIND_WINDOW:
+               case CMD_FIND_SESSION:
+                       fs.wl = cmd_mouse_window(m, &fs.s);
+                       if (fs.wl != NULL) {
+                               fs.w = fs.wl->window;
+                               fs.wp = fs.w->active;
+                       }
+                       break;
+               }
+               if (fs.wp == NULL) {
+                       if (~flags & CMD_FIND_QUIET)
+                               cmdq_error(cmdq, "no mouse target");
+                       goto error;
+               }
+               return (&fs);
+       }
+       copy = xstrdup(target);
+
+       /* Find separators if they exist. */
+       colon = strchr(copy, ':');
+       if (colon != NULL)
+               *colon++ = '\0';
+       if (colon == NULL)
+               period = strchr(copy, '.');
+       else
+               period = strchr(colon, '.');
+       if (period != NULL)
+               *period++ = '\0';
+
+       /* Set session, window and pane parts. */
+       session = window = pane = NULL;
+       if (colon != NULL && period != NULL) {
+               session = copy;
+               window = colon;
+               pane = period;
+       } else if (colon != NULL && period == NULL) {
+               session = copy;
+               window = colon;
+       } else if (colon == NULL && period != NULL) {
+               window = copy;
+               pane = period;
+       } else {
+               if (*copy == '$')
+                       session = copy;
+               else if (*copy == '@')
+                       window = copy;
+               else if (*copy == '%')
+                       pane = copy;
+               else {
+                       switch (type) {
+                       case CMD_FIND_SESSION:
+                               session = copy;
+                               break;
+                       case CMD_FIND_WINDOW:
+                               window = copy;
+                               break;
+                       case CMD_FIND_PANE:
+                               pane = copy;
+                               break;
+                       }
+               }
+       }
+
+       /* Empty is the same as NULL. */
+       if (session != NULL && *session == '\0')
+               session = NULL;
+       if (window != NULL && *window == '\0')
+               window = NULL;
+       if (pane != NULL && *pane == '\0')
+               pane = NULL;
+
+       /* Map though conversion table. */
+       if (session != NULL)
+               session = cmd_find_map_table(cmd_find_session_table, session);
+       if (window != NULL)
+               window = cmd_find_map_table(cmd_find_window_table, window);
+       if (pane != NULL)
+               pane = cmd_find_map_table(cmd_find_pane_table, pane);
+
+       log_debug("target %s (flags %#x): session=%s, window=%s, pane=%s",
+           target, flags, session == NULL ? "none" : session,
+           window == NULL ? "none" : window, pane == NULL ? "none" : pane);
+
+       /* No pane is allowed if want an index. */
+       if (pane != NULL && (flags & CMD_FIND_WINDOW_INDEX)) {
+               if (~flags & CMD_FIND_QUIET)
+                       cmdq_error(cmdq, "can't specify pane here");
+               goto error;
+       }
+
+       /* If the session isn't NULL, look it up. */
+       if (session != NULL) {
+               /* This will fill in session. */
+               if (cmd_find_get_session(&fs, session) != 0)
+                       goto no_session;
+
+               /* If window and pane are NULL, use that session's current. */
+               if (window == NULL && pane == NULL) {
+                       fs.wl = fs.s->curw;
+                       fs.idx = -1;
+                       fs.w = fs.wl->window;
+                       fs.wp = fs.w->active;
+                       goto found;
+               }
+
+               /* If window is present but pane not, find window in session. */
+               if (window != NULL && pane == NULL) {
+                       /* This will fill in winlink and window. */
+                       if (cmd_find_get_window_with_session(&fs, window) != 0)
+                               goto no_window;
+                       if (~flags & CMD_FIND_WINDOW_INDEX)
+                               fs.wp = fs.wl->window->active;
+                       goto found;
+               }
+
+               /* If pane is present but window not, find pane. */
+               if (window == NULL && pane != NULL) {
+                       /* This will fill in winlink and window and pane. */
+                       if (cmd_find_get_pane_with_session(&fs, pane) != 0)
+                               goto no_pane;
+                       goto found;
+               }
+
+               /*
+                * If window and pane are present, find both in session. This
+                * will fill in winlink and window.
+                */
+               if (cmd_find_get_window_with_session(&fs, window) != 0)
+                       goto no_window;
+               /* This will fill in pane. */
+               if (cmd_find_get_pane_with_window(&fs, pane) != 0)
+                       goto no_pane;
+               goto found;
+       }
+
+       /* No session. If window and pane, try them. */
+       if (window != NULL && pane != NULL) {
+               /* This will fill in session, winlink and window. */
+               if (cmd_find_get_window(&fs, window) != 0)
+                       goto no_window;
+               /* This will fill in pane. */
+               if (cmd_find_get_pane_with_window(&fs, pane) != 0)
+                       goto no_pane;
+               goto found;
+       }
+
+       /* If just window is present, try it. */
+       if (window != NULL && pane == NULL) {
+               /* This will fill in session, winlink and window. */
+               if (cmd_find_get_window(&fs, window) != 0)
+                       goto no_window;
+               if (~flags & CMD_FIND_WINDOW_INDEX)
+                       fs.wp = fs.wl->window->active;
+               goto found;
+       }
+
+       /* If just pane is present, try it. */
+       if (window == NULL && pane != NULL) {
+               /* This will fill in session, winlink, window and pane. */
+               if (cmd_find_get_pane(&fs, pane) != 0)
+                       goto no_pane;
+               goto found;
+       }
+
+current:
+       /* None is the current session. */
+       free(copy);
+       if (flags & CMD_FIND_WINDOW_INDEX)
+               current.idx = -1;
+       return (&current);
+
+error:
+       free(copy);
+       return (NULL);
+
+found:
+       free(copy);
+       return (&fs);
+
+no_session:
+       if (~flags & CMD_FIND_QUIET)
+               cmdq_error(cmdq, "can't find session %s", session);
+       goto error;
+
+no_window:
+       if (~flags & CMD_FIND_QUIET)
+               cmdq_error(cmdq, "can't find window %s", window);
+       goto error;
+
+no_pane:
+       if (~flags & CMD_FIND_QUIET)
+               cmdq_error(cmdq, "can't find pane %s", pane);
+       goto error;
+}
+
+/* Log the result. */
+void
+cmd_find_log_state(const char *f, const char *target, struct cmd_find_state 
*fs)
+{
+       log_debug("%s: target %s%s", f, target == NULL ? "none" : target,
+           fs != NULL ? "" : " (failed)");
+       if (fs == NULL)
+               return;
+       if (fs->s != NULL)
+               log_debug("\ts=$%u", fs->s->id);
+       else
+               log_debug("\ts=none");
+       if (fs->wl != NULL) {
+               log_debug("\twl=%u %d w=@%u %s", fs->wl->idx,
+                   fs->wl->window == fs->w, fs->w->id, fs->w->name);
+       } else
+               log_debug("\twl=none");
+       if (fs->wp != NULL)
+               log_debug("\twp=%%%u", fs->wp->id);
+       else
+               log_debug("\twp=none");
+       if (fs->idx != -1)
+               log_debug("\tidx=%d", fs->idx);
+       else
+               log_debug("\tidx=none");
+}
+
+/* Find the current session. */
+struct session *
+cmd_find_current(struct cmd_q *cmdq)
+{
+       struct cmd_find_state   *fs;
+       int                      flags = CMD_FIND_QUIET;
+
+       fs = cmd_find_target(cmdq, NULL, CMD_FIND_SESSION, flags);
+       cmd_find_log_state(__func__, NULL, fs);
+       if (fs == NULL)
+               return (NULL);
+
+       return (fs->s);
+}
+
+/* Find the target session or report an error and return NULL. */
+struct session *
+cmd_find_session(struct cmd_q *cmdq, const char *target, int prefer_unattached)
+{
+       struct cmd_find_state   *fs;
+       int                      flags = 0;
+
+       if (prefer_unattached)
+               flags |= CMD_FIND_PREFER_UNATTACHED;
+
+       fs = cmd_find_target(cmdq, target, CMD_FIND_SESSION, flags);
+       cmd_find_log_state(__func__, target, fs);
+       if (fs == NULL)
+               return (NULL);
+
+       return (fs->s);
+}
+
+/* Find the target window or report an error and return NULL. */
+struct winlink *
+cmd_find_window(struct cmd_q *cmdq, const char *target, struct session **sp)
+{
+       struct cmd_find_state   *fs;
+
+       fs = cmd_find_target(cmdq, target, CMD_FIND_WINDOW, 0);
+       cmd_find_log_state(__func__, target, fs);
+       if (fs == NULL)
+               return (NULL);
+
+       if (sp != NULL)
+               *sp = fs->s;
+       return (fs->wl);
+}
+
+/* Find the target pane and report an error and return NULL. */
+struct winlink *
+cmd_find_pane(struct cmd_q *cmdq, const char *target, struct session **sp,
+    struct window_pane **wpp)
+{
+       struct cmd_find_state   *fs;
+
+       fs = cmd_find_target(cmdq, target, CMD_FIND_PANE, 0);
+       cmd_find_log_state(__func__, target, fs);
+       if (fs == NULL)
+               return (NULL);
+
+       if (sp != NULL)
+               *sp = fs->s;
+       if (wpp != NULL)
+               *wpp = fs->wp;
+       return (fs->wl);
+}
+
+/* Find the target client or report an error and return NULL. */
+struct client *
+cmd_find_client(struct cmd_q *cmdq, const char *target, int quiet)
+{
+       struct client   *c;
+       char            *copy;
+       size_t           size;
+       const char      *path;
+
+       /* A NULL argument means the current client. */
+       if (target == NULL) {
+               c = cmd_find_current_client(cmdq);
+               if (c == NULL && !quiet)
+                       cmdq_error(cmdq, "no current client");
+               return (c);
+       }
+       copy = xstrdup(target);
+
+       /* Trim a single trailing colon if any. */
+       size = strlen(copy);
+       if (size != 0 && copy[size - 1] == ':')
+               copy[size - 1] = '\0';
+
+       /* Check path of each client. */
+       TAILQ_FOREACH(c, &clients, entry) {
+               if (c->session == NULL || c->tty.path == NULL)
+                       continue;
+               path = c->tty.path;
+
+               /* Try for exact match. */
+               if (strcmp(copy, path) == 0)
+                       break;
+
+               /* Try without leading /dev. */
+               if (strncmp(path, _PATH_DEV, (sizeof _PATH_DEV) - 1) != 0)
+                       continue;
+               if (strcmp(copy, path + (sizeof _PATH_DEV) - 1) == 0)
+                       break;
+       }
+
+       /* If no client found, report an error. */
+       if (c == NULL && !quiet)
+               cmdq_error(cmdq, "can't find client %s", copy);
+
+       free(copy);
+       return (c);
+}
+
+/*
+ * Find the target session and window index, whether or not it exists in the
+ * session. Return -2 on error or -1 if no window index is specified. This is
+ * used when parsing an argument for a window target that may not exist (for
+ * example if it is going to be created).
+ */
+int
+cmd_find_index(struct cmd_q *cmdq, const char *target, struct session **sp)
+{
+       struct cmd_find_state   *fs;
+       int                      flags = CMD_FIND_WINDOW_INDEX;
+
+       fs = cmd_find_target(cmdq, target, CMD_FIND_WINDOW, flags);
+       cmd_find_log_state(__func__, target, fs);
+       if (fs == NULL)
+               return (-2);
+
+       if (sp != NULL)
+               *sp = fs->s;
+       return (fs->idx);
+}
diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c
index 785a701..3a26db3 100644
--- a/cmd-load-buffer.c
+++ b/cmd-load-buffer.c
@@ -72,7 +72,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
 
        if (c != NULL && c->session == NULL)
                cwd = c->cwd;
-       else if ((s = cmd_current_session(cmdq, 0)) != NULL)
+       else if ((s = cmd_find_current(cmdq)) != NULL)
                cwd = s->cwd;
        else
                cwd = AT_FDCWD;
diff --git a/cmd-new-session.c b/cmd-new-session.c
index ec292fa..199e82c 100644
--- a/cmd-new-session.c
+++ b/cmd-new-session.c
@@ -137,7 +137,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
                cwd = fd;
        } else if (c != NULL && c->session == NULL)
                cwd = c->cwd;
-       else if ((c0 = cmd_current_client(cmdq)) != NULL)
+       else if ((c0 = cmd_find_client(cmdq, NULL, 1)) != NULL)
                cwd = c0->session->cwd;
        else {
                fd = open(".", O_RDONLY);
diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c
index 368c517..62c3989 100644
--- a/cmd-save-buffer.c
+++ b/cmd-save-buffer.c
@@ -93,7 +93,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
 
        if (c != NULL && c->session == NULL)
                cwd = c->cwd;
-       else if ((s = cmd_current_session(cmdq, 0)) != NULL)
+       else if ((s = cmd_find_current(cmdq)) != NULL)
                cwd = s->cwd;
        else
                cwd = AT_FDCWD;
diff --git a/cmd.c b/cmd.c
index ea1a29d..e8ce932 100644
--- a/cmd.c
+++ b/cmd.c
@@ -116,24 +116,6 @@ const struct cmd_entry *cmd_table[] = {
        NULL
 };
 
-ARRAY_DECL(client_list, struct client *);
-ARRAY_DECL(sessionslist, struct session *);
-
-int             cmd_session_better(struct session *, struct session *, int);
-struct session *cmd_choose_session_list(struct sessionslist *);
-struct session *cmd_choose_session(int);
-struct client  *cmd_choose_client(struct client_list *);
-struct client  *cmd_lookup_client(const char *);
-struct session *cmd_lookup_session(struct cmd_q *, const char *, int *);
-struct winlink *cmd_lookup_window(struct session *, const char *, int *);
-int             cmd_lookup_index(struct session *, const char *, int *);
-struct winlink *cmd_lookup_winlink_windowid(struct session *, const char *);
-struct session *cmd_window_session(struct cmd_q *, struct window *,
-                   struct winlink **);
-struct winlink *cmd_find_window_offset(const char *, struct session *, int *);
-int             cmd_find_index_offset(const char *, struct session *, int *);
-struct window_pane *cmd_find_pane_offset(const char *, struct winlink *);
-
 int
 cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
 {
@@ -332,183 +314,6 @@ cmd_print(struct cmd *cmd, char *buf, size_t len)
        return (off);
 }
 
-/*
- * Figure out the current session. Use: 1) the current session, if the command
- * context has one; 2) the most recently used session containing the pty of the
- * calling client, if any; 3) the session specified in the TMUX variable from
- * the environment (as passed from the client); 4) the most recently used
- * session from all sessions.
- */
-struct session *
-cmd_current_session(struct cmd_q *cmdq, int prefer_unattached)
-{
-       struct client           *c = cmdq->client;
-       struct session          *s;
-       struct sessionslist      ss;
-       struct winlink          *wl;
-       struct window_pane      *wp;
-       const char              *path;
-       int                      found;
-
-       /* Try the queue session. */
-       if (c != NULL && c->session != NULL)
-               return (c->session);
-
-       /*
-        * If the name of the calling client's pty is known, build a list of
-        * the sessions that contain it and if any choose either the first or
-        * the newest.
-        */
-       path = c == NULL ? NULL : c->tty.path;
-       if (path != NULL) {
-               ARRAY_INIT(&ss);
-               RB_FOREACH(s, sessions, &sessions) {
-                       found = 0;
-                       RB_FOREACH(wl, winlinks, &s->windows) {
-                               TAILQ_FOREACH(wp, &wl->window->panes, entry) {
-                                       if (strcmp(wp->tty, path) == 0) {
-                                               found = 1;
-                                               break;
-                                       }
-                               }
-                               if (found)
-                                       break;
-                       }
-                       if (found)
-                               ARRAY_ADD(&ss, s);
-               }
-
-               s = cmd_choose_session_list(&ss);
-               ARRAY_FREE(&ss);
-               if (s != NULL)
-                       return (s);
-       }
-
-       return (cmd_choose_session(prefer_unattached));
-}
-
-/* Is this session better? */
-int
-cmd_session_better(struct session *s, struct session *best,
-    int prefer_unattached)
-{
-       if (best == NULL)
-               return (1);
-       if (prefer_unattached) {
-               if (!(best->flags & SESSION_UNATTACHED) &&
-                   (s->flags & SESSION_UNATTACHED))
-                       return (1);
-               else if ((best->flags & SESSION_UNATTACHED) &&
-                   !(s->flags & SESSION_UNATTACHED))
-                       return (0);
-       }
-       return (timercmp(&s->activity_time, &best->activity_time, >));
-}
-
-/*
- * Find the most recently used session, preferring unattached if the flag is
- * set.
- */
-struct session *
-cmd_choose_session(int prefer_unattached)
-{
-       struct session  *s, *best;
-
-       best = NULL;
-       RB_FOREACH(s, sessions, &sessions) {
-               if (cmd_session_better(s, best, prefer_unattached))
-                       best = s;
-       }
-       return (best);
-}
-
-/* Find the most recently used session from a list. */
-struct session *
-cmd_choose_session_list(struct sessionslist *ss)
-{
-       struct session  *s, *sbest;
-       struct timeval  *tv = NULL;
-       u_int            i;
-
-       sbest = NULL;
-       for (i = 0; i < ARRAY_LENGTH(ss); i++) {
-               if ((s = ARRAY_ITEM(ss, i)) == NULL)
-                       continue;
-
-               if (tv == NULL || timercmp(&s->activity_time, tv, >)) {
-                       sbest = s;
-                       tv = &s->activity_time;
-               }
-       }
-
-       return (sbest);
-}
-
-/*
- * Find the current client. First try the current client if set, then pick the
- * most recently used of the clients attached to the current session if any,
- * then of all clients.
- */
-struct client *
-cmd_current_client(struct cmd_q *cmdq)
-{
-       struct session          *s;
-       struct client           *c;
-       struct client_list       cc;
-
-       if (cmdq->client != NULL && cmdq->client->session != NULL)
-               return (cmdq->client);
-
-       /*
-        * No current client set. Find the current session and return the
-        * newest of its clients.
-        */
-       s = cmd_current_session(cmdq, 0);
-       if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
-               ARRAY_INIT(&cc);
-               TAILQ_FOREACH(c, &clients, entry) {
-                       if (s == c->session)
-                               ARRAY_ADD(&cc, c);
-               }
-
-               c = cmd_choose_client(&cc);
-               ARRAY_FREE(&cc);
-               if (c != NULL)
-                       return (c);
-       }
-
-       ARRAY_INIT(&cc);
-       TAILQ_FOREACH(c, &clients, entry)
-               ARRAY_ADD(&cc, c);
-       c = cmd_choose_client(&cc);
-       ARRAY_FREE(&cc);
-       return (c);
-}
-
-/* Choose the most recently used client from a list. */
-struct client *
-cmd_choose_client(struct client_list *cc)
-{
-       struct client   *c, *cbest;
-       struct timeval  *tv = NULL;
-       u_int            i;
-
-       cbest = NULL;
-       for (i = 0; i < ARRAY_LENGTH(cc); i++) {
-               if ((c = ARRAY_ITEM(cc, i)) == NULL)
-                       continue;
-               if (c->session == NULL)
-                       continue;
-
-               if (tv == NULL || timercmp(&c->activity_time, tv, >)) {
-                       cbest = c;
-                       tv = &c->activity_time;
-               }
-       }
-
-       return (cbest);
-}
-
 /* Adjust current mouse position for a pane. */
 int
 cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
@@ -560,7 +365,8 @@ cmd_mouse_window(struct mouse_event *m, struct session **sp)
 
 /* Get current mouse pane if any. */
 struct window_pane *
-cmd_mouse_pane(struct mouse_event *m, struct session **sp, struct winlink 
**wlp)
+cmd_mouse_pane(struct mouse_event *m, struct session **sp,
+    struct winlink **wlp)
 {
        struct winlink          *wl;
        struct window_pane      *wp;
@@ -577,745 +383,6 @@ cmd_mouse_pane(struct mouse_event *m, struct session 
**sp, struct winlink **wlp)
        return (wp);
 }
 
-/* Find the target client or report an error and return NULL. */
-struct client *
-cmd_find_client(struct cmd_q *cmdq, const char *arg, int quiet)
-{
-       struct client   *c;
-       char            *tmparg;
-       size_t           arglen;
-
-       /* A NULL argument means the current client. */
-       if (arg == NULL) {
-               c = cmd_current_client(cmdq);
-               if (c == NULL && !quiet)
-                       cmdq_error(cmdq, "no clients");
-               return (c);
-       }
-       tmparg = xstrdup(arg);
-
-       /* Trim a single trailing colon if any. */
-       arglen = strlen(tmparg);
-       if (arglen != 0 && tmparg[arglen - 1] == ':')
-               tmparg[arglen - 1] = '\0';
-
-       /* Find the client, if any. */
-       c = cmd_lookup_client(tmparg);
-
-       /* If no client found, report an error. */
-       if (c == NULL && !quiet)
-               cmdq_error(cmdq, "client not found: %s", tmparg);
-
-       free(tmparg);
-       return (c);
-}
-
-/*
- * Lookup a client by device path. Either of a full match and a match without a
- * leading _PATH_DEV ("/dev/") is accepted.
- */
-struct client *
-cmd_lookup_client(const char *name)
-{
-       struct client   *c;
-       const char      *path;
-
-       TAILQ_FOREACH(c, &clients, entry) {
-               if (c->session == NULL || c->tty.path == NULL)
-                       continue;
-               path = c->tty.path;
-
-               /* Check for exact matches. */
-               if (strcmp(name, path) == 0)
-                       return (c);
-
-               /* Check without leading /dev if present. */
-               if (strncmp(path, _PATH_DEV, (sizeof _PATH_DEV) - 1) != 0)
-                       continue;
-               if (strcmp(name, path + (sizeof _PATH_DEV) - 1) == 0)
-                       return (c);
-       }
-
-       return (NULL);
-}
-
-/* Lookup a session by name. If no session is found, NULL is returned. */
-struct session *
-cmd_lookup_session(struct cmd_q *cmdq, const char *name, int *ambiguous)
-{
-       struct session          *s, *sfound;
-       struct window           *w;
-       struct window_pane      *wp;
-
-       *ambiguous = 0;
-
-       /* Look for $id first. */
-       if ((s = session_find_by_id_str(name)) != NULL)
-               return (s);
-
-       /* Try as pane or window id. */
-       if ((wp = window_pane_find_by_id_str(name)) != NULL)
-               return (cmd_window_session(cmdq, wp->window, NULL));
-       if ((w = window_find_by_id_str(name)) != NULL)
-               return (cmd_window_session(cmdq, w, NULL));
-
-       /*
-        * Look for matches. First look for exact matches - session names must
-        * be unique so an exact match can't be ambigious and can just be
-        * returned.
-        */
-       if ((s = session_find(name)) != NULL)
-               return (s);
-
-       /*
-        * Otherwise look for partial matches, returning early if it is found to
-        * be ambiguous.
-        */
-       sfound = NULL;
-       RB_FOREACH(s, sessions, &sessions) {
-               if (strncmp(name, s->name, strlen(name)) == 0 ||
-                   fnmatch(name, s->name, 0) == 0) {
-                       if (sfound != NULL) {
-                               *ambiguous = 1;
-                               return (NULL);
-                       }
-                       sfound = s;
-               }
-       }
-       return (sfound);
-}
-
-/*
- * Lookup a window or return -1 if not found or ambigious. First try as an
- * index and if invalid, use fnmatch or leading prefix. Return NULL but fill in
- * idx if the window index is a valid number but there is no window with that
- * index.
- */
-struct winlink *
-cmd_lookup_window(struct session *s, const char *name, int *ambiguous)
-{
-       struct winlink          *wl, *wlfound;
-       struct window           *w;
-       struct window_pane      *wp;
-       const char              *errstr;
-       u_int                    idx;
-
-       *ambiguous = 0;
-
-       /* Try as pane or window id. */
-       if ((wl = cmd_lookup_winlink_windowid(s, name)) != NULL)
-           return (wl);
-
-       /* Lookup as pane or window id. */
-       if ((wp = window_pane_find_by_id_str(name)) != NULL) {
-               wl = winlink_find_by_window(&s->windows, wp->window);
-               if (wl != NULL)
-                       return (wl);
-       }
-       if ((w = window_find_by_id_str(name)) != NULL) {
-               wl = winlink_find_by_window(&s->windows, w);
-               if (wl != NULL)
-                       return (wl);
-       }
-
-       /* First see if this is a valid window index in this session. */
-       idx = strtonum(name, 0, INT_MAX, &errstr);
-       if (errstr == NULL) {
-               if ((wl = winlink_find_by_index(&s->windows, idx)) != NULL)
-                       return (wl);
-       }
-
-       /* Look for exact matches, error if more than one. */
-       wlfound = NULL;
-       RB_FOREACH(wl, winlinks, &s->windows) {
-               if (strcmp(name, wl->window->name) == 0) {
-                       if (wlfound != NULL) {
-                               *ambiguous = 1;
-                               return (NULL);
-                       }
-                       wlfound = wl;
-               }
-       }
-       if (wlfound != NULL)
-               return (wlfound);
-
-       /* Now look for pattern matches, again error if multiple. */
-       wlfound = NULL;
-       RB_FOREACH(wl, winlinks, &s->windows) {
-               if (strncmp(name, wl->window->name, strlen(name)) == 0 ||
-                   fnmatch(name, wl->window->name, 0) == 0) {
-                       if (wlfound != NULL) {
-                               *ambiguous = 1;
-                               return (NULL);
-                       }
-                       wlfound = wl;
-               }
-       }
-       if (wlfound != NULL)
-               return (wlfound);
-
-       return (NULL);
-}
-
-/*
- * Find a window index - if the window doesn't exist, check if it is a
- * potential index and return it anyway.
- */
-int
-cmd_lookup_index(struct session *s, const char *name, int *ambiguous)
-{
-       struct winlink  *wl;
-       const char      *errstr;
-       u_int            idx;
-
-       idx = strtonum(name, 0, INT_MAX, &errstr);
-       if (errstr == NULL)
-               return (idx);
-
-       if ((wl = cmd_lookup_window(s, name, ambiguous)) != NULL)
-               return (wl->idx);
-       if (*ambiguous)
-               return (-1);
-
-       return (-1);
-}
-
-/* Lookup window id in a session. An initial @ means a window id. */
-struct winlink *
-cmd_lookup_winlink_windowid(struct session *s, const char *arg)
-{
-       const char      *errstr;
-       u_int            windowid;
-
-       if (*arg != '@')
-               return (NULL);
-
-       windowid = strtonum(arg + 1, 0, UINT_MAX, &errstr);
-       if (errstr != NULL)
-               return (NULL);
-       return (winlink_find_by_window_id(&s->windows, windowid));
-}
-
-/* Find session and winlink for window. */
-struct session *
-cmd_window_session(struct cmd_q *cmdq, struct window *w, struct winlink **wlp)
-{
-       struct session          *s;
-       struct sessionslist      ss;
-       struct winlink          *wl;
-
-       /* If this window is in the current session, return that winlink. */
-       s = cmd_current_session(cmdq, 0);
-       if (s != NULL) {
-               wl = winlink_find_by_window(&s->windows, w);
-               if (wl != NULL) {
-                       if (wlp != NULL)
-                               *wlp = wl;
-                       return (s);
-               }
-       }
-
-       /* Otherwise choose from all sessions with this window. */
-       ARRAY_INIT(&ss);
-       RB_FOREACH(s, sessions, &sessions) {
-               if (winlink_find_by_window(&s->windows, w) != NULL)
-                       ARRAY_ADD(&ss, s);
-       }
-       s = cmd_choose_session_list(&ss);
-       ARRAY_FREE(&ss);
-       if (wlp != NULL)
-               *wlp = winlink_find_by_window(&s->windows, w);
-       return (s);
-}
-
-/* Find the target session or report an error and return NULL. */
-struct session *
-cmd_find_session(struct cmd_q *cmdq, const char *arg, int prefer_unattached)
-{
-       struct session  *s;
-       struct client   *c;
-       char            *tmparg;
-       size_t           arglen;
-       int              ambiguous;
-
-       /* A NULL argument means the current session. */
-       if (arg == NULL) {
-               if ((s = cmd_current_session(cmdq, prefer_unattached)) == NULL)
-                       cmdq_error(cmdq, "can't establish current session");
-               return (s);
-       }
-
-       /* Trim a single trailing colon if any. */
-       tmparg = xstrdup(arg);
-       arglen = strlen(tmparg);
-       if (arglen != 0 && tmparg[arglen - 1] == ':')
-               tmparg[arglen - 1] = '\0';
-
-       /* An empty session name is the current session. */
-       if (*tmparg == '\0') {
-               free(tmparg);
-               if ((s = cmd_current_session(cmdq, prefer_unattached)) == NULL)
-                       cmdq_error(cmdq, "can't establish current session");
-               return (s);
-       }
-
-       /* Find the session, if any. */
-       s = cmd_lookup_session(cmdq, tmparg, &ambiguous);
-
-       /* If it doesn't, try to match it as a client. */
-       if (s == NULL && (c = cmd_lookup_client(tmparg)) != NULL)
-               s = c->session;
-
-       /* If no session found, report an error. */
-       if (s == NULL) {
-               if (ambiguous)
-                       cmdq_error(cmdq, "more than one session: %s", tmparg);
-               else
-                       cmdq_error(cmdq, "session not found: %s", tmparg);
-       }
-
-       free(tmparg);
-       return (s);
-}
-
-/* Find the target session and window or report an error and return NULL. */
-struct winlink *
-cmd_find_window(struct cmd_q *cmdq, const char *arg, struct session **sp)
-{
-       struct session  *s;
-       struct winlink  *wl;
-       const char      *winptr;
-       char            *sessptr = NULL;
-       int              ambiguous = 0;
-
-       /*
-        * Find the current session. There must always be a current session, if
-        * it can't be found, report an error.
-        */
-       if ((s = cmd_current_session(cmdq, 0)) == NULL) {
-               cmdq_error(cmdq, "can't establish current session");
-               return (NULL);
-       }
-
-       /* A NULL argument means the current session and window. */
-       if (arg == NULL) {
-               if (sp != NULL)
-                       *sp = s;
-               return (s->curw);
-       }
-
-       /* Time to look at the argument. If it is empty, that is an error. */
-       if (*arg == '\0')
-               goto not_found;
-
-       /* Find the separating colon and split into window and session. */
-       winptr = strchr(arg, ':');
-       if (winptr == NULL)
-               goto no_colon;
-       winptr++;       /* skip : */
-       sessptr = xstrdup(arg);
-       *strchr(sessptr, ':') = '\0';
-
-       /* Try to lookup the session if present. */
-       if (*sessptr != '\0') {
-               if ((s = cmd_lookup_session(cmdq, sessptr, &ambiguous)) == NULL)
-                       goto no_session;
-       }
-       if (sp != NULL)
-               *sp = s;
-
-       /*
-        * Then work out the window. An empty string is the current window,
-        * otherwise try special cases then to look it up in the session.
-        */
-       if (*winptr == '\0')
-               wl = s->curw;
-       else if (winptr[0] == '!' && winptr[1] == '\0')
-               wl = TAILQ_FIRST(&s->lastw);
-       else if (winptr[0] == '^' && winptr[1] == '\0')
-               wl = RB_MIN(winlinks, &s->windows);
-       else if (winptr[0] == '$' && winptr[1] == '\0')
-               wl = RB_MAX(winlinks, &s->windows);
-       else if (winptr[0] == '+' || winptr[0] == '-')
-               wl = cmd_find_window_offset(winptr, s, &ambiguous);
-       else
-               wl = cmd_lookup_window(s, winptr, &ambiguous);
-       if (wl == NULL)
-               goto not_found;
-
-       if (sessptr != NULL)
-               free(sessptr);
-       return (wl);
-
-no_colon:
-       /*
-        * No colon in the string, first try special cases, then as a window
-        * and lastly as a session.
-        */
-       if (arg[0] == '=' && arg[1] == '\0') {
-               if ((wl = cmd_mouse_window(&cmdq->item->mouse, &s)) == NULL) {
-                       cmdq_error(cmdq, "no mouse target");
-                       goto error;
-               }
-       } else if (arg[0] == '!' && arg[1] == '\0') {
-               if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
-                       goto not_found;
-       } else if (arg[0] == '+' || arg[0] == '-') {
-               if ((wl = cmd_find_window_offset(arg, s, &ambiguous)) == NULL)
-                       goto lookup_session;
-       } else if ((wl = cmd_lookup_window(s, arg, &ambiguous)) == NULL)
-               goto lookup_session;
-
-       if (sp != NULL)
-               *sp = s;
-
-       return (wl);
-
-lookup_session:
-       if (ambiguous)
-               goto not_found;
-       if (*arg != '\0' &&
-           (s = cmd_lookup_session(cmdq, arg, &ambiguous)) == NULL)
-               goto no_session;
-
-       if (sp != NULL)
-               *sp = s;
-
-       return (s->curw);
-
-no_session:
-       if (ambiguous)
-               cmdq_error(cmdq, "multiple sessions: %s", arg);
-       else
-               cmdq_error(cmdq, "session not found: %s", arg);
-       goto error;
-
-not_found:
-       if (ambiguous)
-               cmdq_error(cmdq, "multiple windows: %s", arg);
-       else
-               cmdq_error(cmdq, "window not found: %s", arg);
-       goto error;
-
-error:
-       free(sessptr);
-       return (NULL);
-}
-
-struct winlink *
-cmd_find_window_offset(const char *winptr, struct session *s, int *ambiguous)
-{
-       struct winlink  *wl;
-       int              offset = 1;
-
-       if (winptr[1] != '\0')
-               offset = strtonum(winptr + 1, 1, INT_MAX, NULL);
-       if (offset == 0)
-               wl = cmd_lookup_window(s, winptr, ambiguous);
-       else {
-               if (winptr[0] == '+')
-                       wl = winlink_next_by_number(s->curw, s, offset);
-               else
-                       wl = winlink_previous_by_number(s->curw, s, offset);
-       }
-
-       return (wl);
-}
-
-/*
- * Find the target session and window index, whether or not it exists in the
- * session. Return -2 on error or -1 if no window index is specified. This is
- * used when parsing an argument for a window target that may not exist (for
- * example if it is going to be created).
- */
-int
-cmd_find_index(struct cmd_q *cmdq, const char *arg, struct session **sp)
-{
-       struct session  *s;
-       struct winlink  *wl;
-       const char      *winptr;
-       char            *sessptr = NULL;
-       int              idx, ambiguous = 0;
-
-       /*
-        * Find the current session. There must always be a current session, if
-        * it can't be found, report an error.
-        */
-       if ((s = cmd_current_session(cmdq, 0)) == NULL) {
-               cmdq_error(cmdq, "can't establish current session");
-               return (-2);
-       }
-
-       /* A NULL argument means the current session and "no window" (-1). */
-       if (arg == NULL) {
-               if (sp != NULL)
-                       *sp = s;
-               return (-1);
-       }
-
-       /* Time to look at the argument. If it is empty, that is an error. */
-       if (*arg == '\0')
-               goto not_found;
-
-       /* Find the separating colon. If none, assume the current session. */
-       winptr = strchr(arg, ':');
-       if (winptr == NULL)
-               goto no_colon;
-       winptr++;       /* skip : */
-       sessptr = xstrdup(arg);
-       *strchr(sessptr, ':') = '\0';
-
-       /* Try to lookup the session if present. */
-       if (sessptr != NULL && *sessptr != '\0') {
-               if ((s = cmd_lookup_session(cmdq, sessptr, &ambiguous)) == NULL)
-                       goto no_session;
-       }
-       if (sp != NULL)
-               *sp = s;
-
-       /*
-        * Then work out the window. An empty string is a new window otherwise
-        * try to look it up in the session.
-        */
-       if (*winptr == '\0')
-               idx = -1;
-       else if (winptr[0] == '!' && winptr[1] == '\0') {
-               if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
-                       goto not_found;
-               idx = wl->idx;
-       } else if (winptr[0] == '+' || winptr[0] == '-') {
-               if ((idx = cmd_find_index_offset(winptr, s, &ambiguous)) < 0)
-                       goto invalid_index;
-       } else if ((idx = cmd_lookup_index(s, winptr, &ambiguous)) == -1)
-               goto invalid_index;
-
-       free(sessptr);
-       return (idx);
-
-no_colon:
-       /*
-        * No colon in the string, first try special cases, then as a window
-        * and lastly as a session.
-        */
-       if (arg[0] == '!' && arg[1] == '\0') {
-               if ((wl = TAILQ_FIRST(&s->lastw)) == NULL)
-                       goto not_found;
-               idx = wl->idx;
-       } else if (arg[0] == '+' || arg[0] == '-') {
-               if ((idx = cmd_find_index_offset(arg, s, &ambiguous)) < 0)
-                       goto lookup_session;
-       } else if ((idx = cmd_lookup_index(s, arg, &ambiguous)) == -1)
-               goto lookup_session;
-
-       if (sp != NULL)
-               *sp = s;
-
-       return (idx);
-
-lookup_session:
-       if (ambiguous)
-               goto not_found;
-       if (*arg != '\0' &&
-           (s = cmd_lookup_session(cmdq, arg, &ambiguous)) == NULL)
-               goto no_session;
-
-       if (sp != NULL)
-               *sp = s;
-
-       return (-1);
-
-no_session:
-       if (ambiguous)
-               cmdq_error(cmdq, "multiple sessions: %s", arg);
-       else
-               cmdq_error(cmdq, "session not found: %s", arg);
-       free(sessptr);
-       return (-2);
-
-invalid_index:
-       if (ambiguous)
-               goto not_found;
-       cmdq_error(cmdq, "invalid index: %s", arg);
-
-       free(sessptr);
-       return (-2);
-
-not_found:
-       if (ambiguous)
-               cmdq_error(cmdq, "multiple windows: %s", arg);
-       else
-               cmdq_error(cmdq, "window not found: %s", arg);
-       free(sessptr);
-       return (-2);
-}
-
-int
-cmd_find_index_offset(const char *winptr, struct session *s, int *ambiguous)
-{
-       int     idx, offset = 1;
-
-       if (winptr[1] != '\0')
-               offset = strtonum(winptr + 1, 1, INT_MAX, NULL);
-       if (offset == 0)
-               idx = cmd_lookup_index(s, winptr, ambiguous);
-       else {
-               if (winptr[0] == '+') {
-                       if (s->curw->idx == INT_MAX)
-                               idx = cmd_lookup_index(s, winptr, ambiguous);
-                       else
-                               idx = s->curw->idx + offset;
-               } else {
-                       if (s->curw->idx == 0)
-                               idx = cmd_lookup_index(s, winptr, ambiguous);
-                       else
-                               idx = s->curw->idx - offset;
-               }
-       }
-
-       return (idx);
-}
-
-/*
- * Find the target session, window and pane number or report an error and
- * return NULL. The pane number is separated from the session:window by a .,
- * such as mysession:mywindow.0.
- */
-struct winlink *
-cmd_find_pane(struct cmd_q *cmdq,
-    const char *arg, struct session **sp, struct window_pane **wpp)
-{
-       struct session  *s;
-       struct winlink  *wl;
-       const char      *period, *errstr;
-       char            *winptr, *paneptr;
-       u_int            idx;
-
-       /* Get the current session. */
-       if ((s = cmd_current_session(cmdq, 0)) == NULL) {
-               cmdq_error(cmdq, "can't establish current session");
-               return (NULL);
-       }
-       if (sp != NULL)
-               *sp = s;
-
-       /* A NULL argument means the current session, window and pane. */
-       if (arg == NULL) {
-               *wpp = s->curw->window->active;
-               return (s->curw);
-       }
-
-       /* Lookup as pane id. */
-       if ((*wpp = window_pane_find_by_id_str(arg)) != NULL) {
-               s = cmd_window_session(cmdq, (*wpp)->window, &wl);
-               if (sp != NULL)
-                       *sp = s;
-               return (wl);
-       }
-
-       /* Look for a separating period. */
-       if ((period = strrchr(arg, '.')) == NULL)
-               goto no_period;
-
-       /* Pull out the window part and parse it. */
-       winptr = xstrdup(arg);
-       winptr[period - arg] = '\0';
-       if (*winptr == '\0')
-               wl = s->curw;
-       else if ((wl = cmd_find_window(cmdq, winptr, sp)) == NULL)
-               goto error;
-
-       /* Find the pane section and look it up. */
-       paneptr = winptr + (period - arg) + 1;
-       if (*paneptr == '\0')
-               *wpp = wl->window->active;
-       else if (paneptr[0] == '+' || paneptr[0] == '-')
-               *wpp = cmd_find_pane_offset(paneptr, wl);
-       else if (paneptr[0] == '!' && paneptr[1] == '\0') {
-               if (wl->window->last == NULL) {
-                       cmdq_error(cmdq, "no last pane");
-                       goto error;
-               }
-               *wpp = wl->window->last;
-       } else {
-               idx = strtonum(paneptr, 0, INT_MAX, &errstr);
-               if (errstr != NULL)
-                       goto lookup_string;
-               *wpp = window_pane_at_index(wl->window, idx);
-               if (*wpp == NULL)
-                       goto lookup_string;
-       }
-
-       free(winptr);
-       return (wl);
-
-lookup_string:
-       /* Try pane string description. */
-       if ((*wpp = window_find_string(wl->window, paneptr)) == NULL) {
-               cmdq_error(cmdq, "can't find pane: %s", paneptr);
-               goto error;
-       }
-
-       free(winptr);
-       return (wl);
-
-no_period:
-       /* Check mouse event. */
-       if (arg[0] == '=' && arg[1] == '\0') {
-               *wpp = cmd_mouse_pane(&cmdq->item->mouse, &s, &wl);
-               if (*wpp == NULL) {
-                       cmdq_error(cmdq, "no mouse target");
-                       return (NULL);
-               }
-               if (sp != NULL)
-                       *sp = s;
-               return (wl);
-       }
-
-       /* Try as a pane number alone. */
-       idx = strtonum(arg, 0, INT_MAX, &errstr);
-       if (errstr != NULL)
-               goto lookup_window;
-
-       /* Try index in the current session and window. */
-       if ((*wpp = window_pane_at_index(s->curw->window, idx)) == NULL)
-               goto lookup_window;
-
-       return (s->curw);
-
-lookup_window:
-       /* Try pane string description. */
-       if ((*wpp = window_find_string(s->curw->window, arg)) != NULL)
-               return (s->curw);
-
-       /* Try as a window and use the active pane. */
-       if ((wl = cmd_find_window(cmdq, arg, sp)) != NULL)
-               *wpp = wl->window->active;
-       return (wl);
-
-error:
-       free(winptr);
-       return (NULL);
-}
-
-struct window_pane *
-cmd_find_pane_offset(const char *paneptr, struct winlink *wl)
-{
-       struct window           *w = wl->window;
-       struct window_pane      *wp = w->active;
-       u_int                    offset = 1;
-
-       if (paneptr[1] != '\0')
-               offset = strtonum(paneptr + 1, 1, INT_MAX, NULL);
-       if (offset > 0) {
-               if (paneptr[0] == '+')
-                       wp = window_pane_next_by_number(w, wp, offset);
-               else
-                       wp = window_pane_previous_by_number(w, wp, offset);
-       }
-
-       return (wp);
-}
-
 /* Replace the first %% or %idx in template by s. */
 char *
 cmd_template_replace(const char *template, const char *s, int idx)
diff --git a/tmux.1 b/tmux.1
index 68e9b9d..cd7ec39 100644
--- a/tmux.1
+++ b/tmux.1
@@ -358,8 +358,9 @@ argument with one of
 or
 .Ar target-pane .
 These specify the client, session, window or pane which a command should 
affect.
+.Pp
 .Ar target-client
-is the name of the
+should be the name of the
 .Xr pty 4
 file to which the client is connected, for example either of
 .Pa /dev/ttyp1
@@ -367,27 +368,35 @@ or
 .Pa ttyp1
 for the client attached to
 .Pa /dev/ttyp1 .
-If no client is specified, the current client is chosen, if possible, or an
-error is reported.
+If no client is specified,
+.Nm
+attempts to work out the client currently in use; if that fails, an error is
+reported.
 Clients may be listed with the
 .Ic list-clients
 command.
 .Pp
 .Ar target-session
-is the session id prefixed with a $, the name of a session (as listed by the
+is tried as, in order:
+.Bl -enum -offset Ds
+.It
+A session ID prefixed with a $.
+.It
+An exact name of a session (as listed by the
 .Ic list-sessions
-command), or the name of a client with the same syntax as
-.Ar target-client ,
-in which case the session attached to the client is used.
-When looking for the session name,
-.Nm
-initially searches for an exact match; if none is found, the session names
-are checked for any for which
-.Ar target-session
-is a prefix or for which it matches as an
+command).
+.It
+The start of a session name, for example
+.Ql mysess
+would match a session named
+.Ql mysession .
+.It
+An
 .Xr fnmatch 3
-pattern.
-If a single match is found, it is used as the target session; multiple matches
+pattern which is matched against the session name.
+.El
+.Pp
+If a single session is found, it is used as the target session; multiple 
matches
 produce an error.
 If a session is omitted, the current session is used if available; if no
 current session is available, the most recently used is chosen.
@@ -400,12 +409,29 @@ follows the same rules as for
 .Ar target-session ,
 and
 .Em window
-is looked for in order: as a window index, for example mysession:1;
-as a window ID, such as @1;
-as an exact window name, such as mysession:mywindow; then as an
+is looked for in order as:
+.Bl -enum -offset Ds
+.It
+A special token, listed below.
+.It
+A window index, for example
+.Ql mysession:1
+is window 1 in session
+.Ql mysession .
+.It
+A window ID, such as @1.
+.It
+An exact window name, such as
+.Ql mysession:mywindow .
+.It
+The start of a window name, such as
+.Ql mysession:mywin .
+.It
+As an
 .Xr fnmatch 3
-pattern or the start of a window name, such as mysession:mywin* or
-mysession:mywin.
+pattern matched against the window name.
+.El
+.Pp
 An empty window name specifies the next unused index if appropriate (for
 example the
 .Ic new-window
@@ -415,53 +441,50 @@ commands)
 otherwise the current window in
 .Em session
 is chosen.
-The special character
-.Ql \&!
-uses the last (previously current) window,
-.Ql ^
-selects the highest numbered window,
-.Ql $
-selects the lowest numbered window, and
-.Ql +
-and
-.Ql -
-select the next window or the previous window by number.
-When the argument does not contain a colon,
-.Nm
-first attempts to parse it as window; if that fails, an attempt is made to
-match a session.
+.Pp
+The following special tokens are available to indicate particular windows. Each
+has a single-character alternative form.
+.Bl -column "XXXXXXXXXX" "X"
+.It Sy "Token" Ta Sy "" Ta Sy "Meaning"
+.It Li "{start}" Ta "^" Ta "The lowest-numbered window"
+.It Li "{end}" Ta "$" Ta "The highest-numbered window"
+.It Li "{last}" Ta "!" Ta "The last (previously current) window"
+.It Li "{next}" Ta "+" Ta "The next window by number"
+.It Li "{previous}" Ta "-" Ta "The previous window by number"
+.It Li "{mouse}" Ta "=" Ta "The window where the mouse event happened"
+.El
 .Pp
 .Ar target-pane
-takes a similar form to
+may be a
+pane ID or takes a similar form to
 .Ar target-window
-but with the optional addition of a period followed by a pane index, for
-example: mysession:mywindow.1.
+but with the optional addition of a period followed by a pane index or pane ID,
+for example:
+.Ql mysession:mywindow.1 .
 If the pane index is omitted, the currently active pane in the specified
 window is used.
-If neither a colon nor period appears,
-.Nm
-first attempts to use the argument as a pane index; if that fails, it is looked
-up as for
-.Ar target-window .
-A
-.Ql + ,
-.Ql -
-or
-.Ql \&!
-indicate the next, previous or last pane.
-One of the strings
-.Em top ,
-.Em bottom ,
-.Em left ,
-.Em right ,
-.Em top-left ,
-.Em top-right ,
-.Em bottom-left
-or
-.Em bottom-right
-may be used instead of a pane index.
+The following special tokens are available for the pane index:
+.Bl -column "XXXXXXXXXXXXXX" "X"
+.It Sy "Token" Ta Sy "" Ta Sy "Meaning"
+.It Li "{last}" Ta "!" Ta "The last (previously active) pane"
+.It Li "{next}" Ta "+" Ta "The next pane by number"
+.It Li "{previous}" Ta "-" Ta "The previous pane by number"
+.It Li "{top}" Ta "" Ta "The top pane"
+.It Li "{bottom}" Ta "" Ta "The bottom pane"
+.It Li "{left}" Ta "" Ta "The leftmost pane"
+.It Li "{right}" Ta "" Ta "The rightmost pane"
+.It Li "{top-left}" Ta "" Ta "The top-left pane"
+.It Li "{top-right}" Ta "" Ta "The top-right pane"
+.It Li "{bottom-left}" Ta "" Ta "The bottom-left pane"
+.It Li "{bottom-right}" Ta "" Ta "The bottom-right pane"
+.It Li "{up}" Ta "" Ta "The pane above the active pane"
+.It Li "{down}" Ta "" Ta "The pane below the active pane"
+.It Li "{left}" Ta "" Ta "The pane to the left of the active pane"
+.It Li "{right}" Ta "" Ta "The pane to the right of the active pane"
+.It Li "{mouse}" Ta "=" Ta "The pane where the mouse event happened"
+.El
 .Pp
-The special characters
+The tokens
 .Ql +
 and
 .Ql -
@@ -470,19 +493,34 @@ may be followed by an offset, for example:
 select-window -t:+2
 .Ed
 .Pp
-When dealing with a session that doesn't contain sequential window indexes,
-they will be correctly skipped.
-.Pp
-.Nm
-also gives each pane created in a server an identifier consisting of a
-.Ql %
-and a number, starting from zero.
-A pane's identifier is unique for the life of the
+Sessions, window and panes are each numbered with a unique ID; session IDs are
+prefixed with a
+.Ql $ ,
+windows with a
+.Ql @ ,
+and panes with a
+.Ql % .
+These are unique and are unchanged for the life of the session, window or pane
+in the
 .Nm
-server and is passed to the child process of the pane in the
+server.
+The pane ID is passed to the child process of the pane in the
 .Ev TMUX_PANE
 environment variable.
-It may be used alone to target a pane or the window containing it.
+IDs may be displayed using the
+.Ql session_id ,
+.Ql window_id ,
+or
+.Ql pane_id
+formats (see the
+.Sx FORMATS
+section) and the
+.Ic display-message ,
+.Ic list-sessions ,
+.Ic list-windows
+or
+.Ic list-panes
+commands.
 .Pp
 .Ar shell-command
 arguments are
@@ -3144,7 +3182,9 @@ The following mouse events are available:
 Each should be suffixed with a location, for example
 .Ql MouseDown1Status .
 .Pp
-The special character
+The special token
+.Ql {mouse}
+or
 .Ql =
 may be used as
 .Ar target-window
diff --git a/tmux.h b/tmux.h
index 170ad69..ee36f4b 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1740,8 +1740,19 @@ size_t            args_print(struct args *, char *, 
size_t);
 int             args_has(struct args *, u_char);
 void            args_set(struct args *, u_char, const char *);
 const char     *args_get(struct args *, u_char);
-long long       args_strtonum(
-                   struct args *, u_char, long long, long long, char **);
+long long       args_strtonum(struct args *, u_char, long long, long long,
+                    char **);
+
+/* cmd-find.c */
+struct session *cmd_find_current(struct cmd_q *);
+struct session *cmd_find_session(struct cmd_q *, const char *, int);
+struct winlink *cmd_find_window(struct cmd_q *, const char *,
+                    struct session **);
+struct winlink *cmd_find_pane(struct cmd_q *, const char *, struct session **,
+                    struct window_pane **);
+struct client  *cmd_find_client(struct cmd_q *, const char *, int);
+int             cmd_find_index(struct cmd_q *, const char *,
+                    struct session **);
 
 /* cmd.c */
 int             cmd_pack_argv(int, char **, char *, size_t);
@@ -1756,16 +1767,6 @@ int               cmd_mouse_at(struct window_pane *, 
struct mouse_event *,
 struct winlink *cmd_mouse_window(struct mouse_event *, struct session **);
 struct window_pane *cmd_mouse_pane(struct mouse_event *, struct session **,
                     struct winlink **);
-struct session *cmd_current_session(struct cmd_q *, int);
-struct client  *cmd_current_client(struct cmd_q *);
-struct client  *cmd_find_client(struct cmd_q *, const char *, int);
-struct session *cmd_find_session(struct cmd_q *, const char *, int);
-struct winlink *cmd_find_window(struct cmd_q *, const char *,
-                    struct session **);
-int             cmd_find_index(struct cmd_q *, const char *,
-                    struct session **);
-struct winlink *cmd_find_pane(struct cmd_q *, const char *, struct session **,
-                    struct window_pane **);
 char           *cmd_template_replace(const char *, const char *, int);
 extern const struct cmd_entry *cmd_table[];
 extern const struct cmd_entry cmd_attach_session_entry;


commit a70762c9b50e9d9249fa9a56233c0df4129c82fc
Author: nicm <nicm>
Commit: nicm <nicm>

    If the requested pane is already active, do not unzoom the window (or do
    anything else). Prevents mouse clicking when zoomed causing unzoom,
    reported by Jose Antonio Delgado Alfonso (with a different fix).
---
 cmd-select-pane.c |   24 +++++++++++++++---------
 1 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/cmd-select-pane.c b/cmd-select-pane.c
index c84b414..e7f2249 100644
--- a/cmd-select-pane.c
+++ b/cmd-select-pane.c
@@ -77,12 +77,6 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
        if ((wl = cmd_find_pane(cmdq, args_get(args, 't'), NULL, &wp)) == NULL)
                return (CMD_RETURN_ERROR);
 
-       server_unzoom_window(wp->window);
-       if (!window_pane_visible(wp)) {
-               cmdq_error(cmdq, "pane not visible");
-               return (CMD_RETURN_ERROR);
-       }
-
        if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
                if (args_has(args, 'P')) {
                        style = args_get(args, 'P');
@@ -111,11 +105,23 @@ cmd_select_pane_exec(struct cmd *self, struct cmd_q *cmdq)
                return (CMD_RETURN_ERROR);
        }
 
-       if (args_has(self->args, 'e'))
+       if (args_has(self->args, 'e')) {
                wp->flags &= ~PANE_INPUTOFF;
-       else if (args_has(self->args, 'd'))
+               return (CMD_RETURN_NORMAL);
+       }
+       if (args_has(self->args, 'd')) {
                wp->flags |= PANE_INPUTOFF;
-       else if (window_set_active_pane(wl->window, wp)) {
+               return (CMD_RETURN_NORMAL);
+       }
+
+       if (wp == wl->window->active)
+               return (CMD_RETURN_NORMAL);
+       server_unzoom_window(wp->window);
+       if (!window_pane_visible(wp)) {
+               cmdq_error(cmdq, "pane not visible");
+               return (CMD_RETURN_ERROR);
+       }
+       if (window_set_active_pane(wl->window, wp)) {
                server_status_window(wl->window);
                server_redraw_window_borders(wl->window);
        }


commit 5bd5c9c84e4bde3461a50f15e387c5e9fb78d7cb
Author: nicm <nicm>
Commit: nicm <nicm>

    Remove panes from layout if spawning them fails, reported by Anthony J
    Bentley.
---
 cmd-split-window.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/cmd-split-window.c b/cmd-split-window.c
index 680b156..4e85a0f 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -147,6 +147,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
                goto error;
        }
        new_wp = window_add_pane(w, hlimit);
+       layout_assign_pane(lc, new_wp);
 
        path = NULL;
        if (cmdq->client != NULL && cmdq->client->session == NULL)
@@ -159,7 +160,6 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
        if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, &env,
            s->tio, &cause) != 0)
                goto error;
-       layout_assign_pane(lc, new_wp);
 
        server_redraw_window(w);
 
@@ -194,8 +194,10 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq)
 
 error:
        environ_free(&env);
-       if (new_wp != NULL)
+       if (new_wp != NULL) {
+               layout_close_pane(new_wp);
                window_remove_pane(w, new_wp);
+       }
        cmdq_error(cmdq, "create pane failed: %s", cause);
        free(cause);
        if (fd != -1)


commit 05e7fbd60fcd1f5c82049dc2f416e7dd42577cfd
Author: nicm <nicm>
Commit: nicm <nicm>

    Get rid of window_choose_list type.
---
 window.c |   92 ++++++++++++++++++++++++++++++++++---------------------------
 1 files changed, 51 insertions(+), 41 deletions(-)

diff --git a/window.c b/window.c
index c60404d..31f20a1 100644
--- a/window.c
+++ b/window.c
@@ -49,8 +49,6 @@
  * it reaches zero.
  */
 
-ARRAY_DECL(window_pane_list, struct window_pane *);
-
 /* Global window list. */
 struct windows windows;
 
@@ -64,7 +62,7 @@ void  window_pane_timer_callback(int, short, void *);
 void   window_pane_read_callback(struct bufferevent *, void *);
 void   window_pane_error_callback(struct bufferevent *, short, void *);
 
-struct window_pane *window_pane_choose_best(struct window_pane_list *);
+struct window_pane *window_pane_choose_best(struct window_pane **, u_int);
 
 RB_GENERATE(windows, window, entry, window_cmp);
 
@@ -256,7 +254,7 @@ winlink_stack_remove(struct winlink_stack *stack, struct 
winlink *wl)
 }
 
 struct window *
-window_find_by_id_str(const char* s)
+window_find_by_id_str(const char *s)
 {
        const char      *errstr;
        u_int            id;
@@ -1149,17 +1147,17 @@ window_pane_search(struct window_pane *wp, const char 
*searchstr,
 
 /* Get MRU pane from a list. */
 struct window_pane *
-window_pane_choose_best(struct window_pane_list *list)
+window_pane_choose_best(struct window_pane **list, u_int size)
 {
        struct window_pane      *next, *best;
        u_int                    i;
 
-       if (ARRAY_LENGTH(list) == 0)
+       if (size == 0)
                return (NULL);
 
-       best = ARRAY_FIRST(list);
-       for (i = 1; i < ARRAY_LENGTH(list); i++) {
-               next = ARRAY_ITEM(list, i);
+       best = list[0];
+       for (i = 1; i < size; i++) {
+               next = list[i];
                if (next->active_point > best->active_point)
                        best = next;
        }
@@ -1173,14 +1171,15 @@ window_pane_choose_best(struct window_pane_list *list)
 struct window_pane *
 window_pane_find_up(struct window_pane *wp)
 {
-       struct window_pane      *next, *best;
-       u_int                    edge, left, right, end;
-       struct window_pane_list  list;
+       struct window_pane      *next, *best, **list;
+       u_int                    edge, left, right, end, size;
        int                      found;
 
        if (wp == NULL || !window_pane_visible(wp))
                return (NULL);
-       ARRAY_INIT(&list);
+
+       list = NULL;
+       size = 0;
 
        edge = wp->yoff;
        if (edge == 0)
@@ -1203,12 +1202,14 @@ window_pane_find_up(struct window_pane *wp)
                        found = 1;
                else if (end >= left && end <= right)
                        found = 1;
-               if (found)
-                       ARRAY_ADD(&list, next);
+               if (!found)
+                       continue;
+               list = xreallocarray(list, size + 1, sizeof *list);
+               list[size++] = next;
        }
 
-       best = window_pane_choose_best(&list);
-       ARRAY_FREE(&list);
+       best = window_pane_choose_best(list, size);
+       free(list);
        return (best);
 }
 
@@ -1216,14 +1217,15 @@ window_pane_find_up(struct window_pane *wp)
 struct window_pane *
 window_pane_find_down(struct window_pane *wp)
 {
-       struct window_pane      *next, *best;
-       u_int                    edge, left, right, end;
-       struct window_pane_list  list;
+       struct window_pane      *next, *best, **list;
+       u_int                    edge, left, right, end, size;
        int                      found;
 
        if (wp == NULL || !window_pane_visible(wp))
                return (NULL);
-       ARRAY_INIT(&list);
+
+       list = NULL;
+       size = 0;
 
        edge = wp->yoff + wp->sy + 1;
        if (edge >= wp->window->sy)
@@ -1246,12 +1248,14 @@ window_pane_find_down(struct window_pane *wp)
                        found = 1;
                else if (end >= left && end <= right)
                        found = 1;
-               if (found)
-                       ARRAY_ADD(&list, next);
+               if (!found)
+                       continue;
+               list = xreallocarray(list, size + 1, sizeof *list);
+               list[size++] = next;
        }
 
-       best = window_pane_choose_best(&list);
-       ARRAY_FREE(&list);
+       best = window_pane_choose_best(list, size);
+       free(list);
        return (best);
 }
 
@@ -1259,14 +1263,15 @@ window_pane_find_down(struct window_pane *wp)
 struct window_pane *
 window_pane_find_left(struct window_pane *wp)
 {
-       struct window_pane      *next, *best;
-       u_int                    edge, top, bottom, end;
-       struct window_pane_list  list;
+       struct window_pane      *next, *best, **list;
+       u_int                    edge, top, bottom, end, size;
        int                      found;
 
        if (wp == NULL || !window_pane_visible(wp))
                return (NULL);
-       ARRAY_INIT(&list);
+
+       list = NULL;
+       size = 0;
 
        edge = wp->xoff;
        if (edge == 0)
@@ -1289,12 +1294,14 @@ window_pane_find_left(struct window_pane *wp)
                        found = 1;
                else if (end >= top && end <= bottom)
                        found = 1;
-               if (found)
-                       ARRAY_ADD(&list, next);
+               if (!found)
+                       continue;
+               list = xreallocarray(list, size + 1, sizeof *list);
+               list[size++] = next;
        }
 
-       best = window_pane_choose_best(&list);
-       ARRAY_FREE(&list);
+       best = window_pane_choose_best(list, size);
+       free(list);
        return (best);
 }
 
@@ -1302,14 +1309,15 @@ window_pane_find_left(struct window_pane *wp)
 struct window_pane *
 window_pane_find_right(struct window_pane *wp)
 {
-       struct window_pane      *next, *best;
-       u_int                    edge, top, bottom, end;
-       struct window_pane_list  list;
+       struct window_pane      *next, *best, **list;
+       u_int                    edge, top, bottom, end, size;
        int                      found;
 
        if (wp == NULL || !window_pane_visible(wp))
                return (NULL);
-       ARRAY_INIT(&list);
+
+       list = NULL;
+       size = 0;
 
        edge = wp->xoff + wp->sx + 1;
        if (edge >= wp->window->sx)
@@ -1332,12 +1340,14 @@ window_pane_find_right(struct window_pane *wp)
                        found = 1;
                else if (end >= top && end <= bottom)
                        found = 1;
-               if (found)
-                       ARRAY_ADD(&list, next);
+               if (!found)
+                       continue;
+               list = xreallocarray(list, size + 1, sizeof *list);
+               list[size++] = next;
        }
 
-       best = window_pane_choose_best(&list);
-       ARRAY_FREE(&list);
+       best = window_pane_choose_best(list, size);
+       free(list);
        return (best);
 }
 


commit 1d1208e335644ee10ebe47363b2ca8db45bf9142
Author: nicm <nicm>
Commit: nicm <nicm>

    Fix some char* -> char *.
---
 cfg.c          |   18 +++++++++---------
 key-bindings.c |    4 ++--
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/cfg.c b/cfg.c
index 54ba7f7..bacec99 100644
--- a/cfg.c
+++ b/cfg.c
@@ -27,12 +27,12 @@
 
 #include "tmux.h"
 
-struct cmd_q           *cfg_cmd_q;
-int                     cfg_finished;
-int                     cfg_references;
-char**                  cfg_causes;
-u_int                   cfg_ncauses;
-struct client          *cfg_client;
+struct cmd_q            *cfg_cmd_q;
+int                      cfg_finished;
+int                      cfg_references;
+char                   **cfg_causes;
+u_int                    cfg_ncauses;
+struct client           *cfg_client;
 
 int
 load_cfg(const char *path, struct cmd_q *cmdq, char **cause)
@@ -114,10 +114,10 @@ cfg_default_done(unused struct cmd_q *cmdq)
 }
 
 void
-cfg_add_cause(const char* fmt, ...)
+cfg_add_cause(const char *fmt, ...)
 {
-       va_list ap;
-       char*   msg;
+       va_list  ap;
+       char    *msg;
 
        va_start(ap, fmt);
        xvasprintf(&msg, fmt, ap);
diff --git a/key-bindings.c b/key-bindings.c
index 670300a..d56428b 100644
--- a/key-bindings.c
+++ b/key-bindings.c
@@ -144,7 +144,7 @@ key_bindings_remove_table(const char *name)
 void
 key_bindings_init(void)
 {
-       static const char* defaults[] = {
+       static const char *defaults[] = {
                "bind C-b send-prefix",
                "bind C-o rotate-window",
                "bind C-z suspend-client",
@@ -225,7 +225,7 @@ key_bindings_init(void)
        };
        u_int            i;
        struct cmd_list *cmdlist;
-       char*            cause;
+       char            *cause;
        int              error;
        struct cmd_q    *cmdq;
 


-----------------------------------------------------------------------

Summary of changes:
 Makefile.am           |    1 +
 cfg.c                 |   18 +-
 cmd-choose-buffer.c   |    2 +-
 cmd-choose-client.c   |    2 +-
 cmd-choose-tree.c     |    2 +-
 cmd-display-message.c |    2 +-
 cmd-find-window.c     |    2 +-
 cmd-find.c            | 1114 +++++++++++++++++++++++++++++++++++++++++++++++++
 cmd-load-buffer.c     |    2 +-
 cmd-new-session.c     |    2 +-
 cmd-save-buffer.c     |    2 +-
 cmd-select-pane.c     |   24 +-
 cmd-split-window.c    |    6 +-
 cmd.c                 |  937 +-----------------------------------------
 key-bindings.c        |    4 +-
 tmux.1                |  182 +++++----
 tmux.h                |   25 +-
 window.c              |   92 +++--
 18 files changed, 1330 insertions(+), 1089 deletions(-)
 create mode 100644 cmd-find.c


hooks/post-receive
-- 
tmux

------------------------------------------------------------------------------
One dashboard for servers and applications across Physical-Virtual-Cloud 
Widest out-of-the-box monitoring support with 50+ applications
Performance metrics, stats and reports that give you Actionable Insights
Deep dive visibility with transaction tracing using APM Insight.
http://ad.doubleclick.net/ddm/clk/290420510;117567292;y
_______________________________________________
tmux-cvs mailing list
tmux-cvs@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-cvs

Reply via email to