4 * Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
29 static int cmd_find_session_better(struct session
*, struct session
*,
31 static struct session
*cmd_find_best_session(struct session
**, u_int
, int);
32 static int cmd_find_best_session_with_window(struct cmd_find_state
*);
33 static int cmd_find_best_winlink_with_window(struct cmd_find_state
*);
35 static const char *cmd_find_map_table(const char *[][2], const char *);
37 static void cmd_find_log_state(const char *, struct cmd_find_state
*);
38 static int cmd_find_get_session(struct cmd_find_state
*, const char *);
39 static int cmd_find_get_window(struct cmd_find_state
*, const char *, int);
40 static int cmd_find_get_window_with_session(struct cmd_find_state
*,
42 static int cmd_find_get_pane(struct cmd_find_state
*, const char *, int);
43 static int cmd_find_get_pane_with_session(struct cmd_find_state
*,
45 static int cmd_find_get_pane_with_window(struct cmd_find_state
*,
48 static const char *cmd_find_session_table
[][2] = {
51 static const char *cmd_find_window_table
[][2] = {
56 { "{previous}", "-" },
59 static const char *cmd_find_pane_table
[][2] = {
62 { "{previous}", "-" },
64 { "{bottom}", "bottom" },
66 { "{right}", "right" },
67 { "{top-left}", "top-left" },
68 { "{top-right}", "top-right" },
69 { "{bottom-left}", "bottom-left" },
70 { "{bottom-right}", "bottom-right" },
71 { "{up-of}", "{up-of}" },
72 { "{down-of}", "{down-of}" },
73 { "{left-of}", "{left-of}" },
74 { "{right-of}", "{right-of}" },
78 /* Find pane containing client if any. */
79 static struct window_pane
*
80 cmd_find_inside_pane(struct client
*c
)
82 struct window_pane
*wp
;
83 struct environ_entry
*envent
;
88 RB_FOREACH(wp
, window_pane_tree
, &all_window_panes
) {
89 if (wp
->fd
!= -1 && strcmp(wp
->tty
, c
->ttyname
) == 0)
93 envent
= environ_find(c
->environ
, "TMUX_PANE");
95 wp
= window_pane_find_by_id_str(envent
->value
);
98 log_debug("%s: got pane %%%u (%s)", __func__
, wp
->id
, wp
->tty
);
102 /* Is this client better? */
104 cmd_find_client_better(struct client
*c
, struct client
*than
)
108 return (timercmp(&c
->activity_time
, &than
->activity_time
, >));
111 /* Find best client for session. */
113 cmd_find_best_client(struct session
*s
)
115 struct client
*c_loop
, *c
;
117 if (s
->attached
== 0)
121 TAILQ_FOREACH(c_loop
, &clients
, entry
) {
122 if (c_loop
->session
== NULL
)
124 if (s
!= NULL
&& c_loop
->session
!= s
)
126 if (cmd_find_client_better(c_loop
, c
))
132 /* Is this session better? */
134 cmd_find_session_better(struct session
*s
, struct session
*than
, int flags
)
140 if (flags
& CMD_FIND_PREFER_UNATTACHED
) {
141 attached
= (than
->attached
!= 0);
142 if (attached
&& s
->attached
== 0)
144 else if (!attached
&& s
->attached
!= 0)
147 return (timercmp(&s
->activity_time
, &than
->activity_time
, >));
150 /* Find best session from a list, or all if list is NULL. */
151 static struct session
*
152 cmd_find_best_session(struct session
**slist
, u_int ssize
, int flags
)
154 struct session
*s_loop
, *s
;
157 log_debug("%s: %u sessions to try", __func__
, ssize
);
161 for (i
= 0; i
< ssize
; i
++) {
162 if (cmd_find_session_better(slist
[i
], s
, flags
))
166 RB_FOREACH(s_loop
, sessions
, &sessions
) {
167 if (cmd_find_session_better(s_loop
, s
, flags
))
174 /* Find best session and winlink for window. */
176 cmd_find_best_session_with_window(struct cmd_find_state
*fs
)
178 struct session
**slist
= NULL
;
182 log_debug("%s: window is @%u", __func__
, fs
->w
->id
);
185 RB_FOREACH(s
, sessions
, &sessions
) {
186 if (!session_has(s
, fs
->w
))
188 slist
= xreallocarray(slist
, ssize
+ 1, sizeof *slist
);
193 fs
->s
= cmd_find_best_session(slist
, ssize
, fs
->flags
);
197 return (cmd_find_best_winlink_with_window(fs
));
205 * Find the best winlink for a window (the current if it contains the window,
206 * otherwise the first).
209 cmd_find_best_winlink_with_window(struct cmd_find_state
*fs
)
211 struct winlink
*wl
, *wl_loop
;
213 log_debug("%s: window is @%u", __func__
, fs
->w
->id
);
216 if (fs
->s
->curw
!= NULL
&& fs
->s
->curw
->window
== fs
->w
)
219 RB_FOREACH(wl_loop
, winlinks
, &fs
->s
->windows
) {
220 if (wl_loop
->window
== fs
->w
) {
229 fs
->idx
= fs
->wl
->idx
;
233 /* Maps string in table. */
235 cmd_find_map_table(const char *table
[][2], const char *s
)
239 for (i
= 0; table
[i
][0] != NULL
; i
++) {
240 if (strcmp(s
, table
[i
][0]) == 0)
241 return (table
[i
][1]);
246 /* Find session from string. Fills in s. */
248 cmd_find_get_session(struct cmd_find_state
*fs
, const char *session
)
250 struct session
*s
, *s_loop
;
253 log_debug("%s: %s", __func__
, session
);
255 /* Check for session ids starting with $. */
256 if (*session
== '$') {
257 fs
->s
= session_find_by_id_str(session
);
263 /* Look for exactly this session. */
264 fs
->s
= session_find(session
);
268 /* Look for as a client. */
269 c
= cmd_find_client(NULL
, session
, 1);
270 if (c
!= NULL
&& c
->session
!= NULL
) {
275 /* Stop now if exact only. */
276 if (fs
->flags
& CMD_FIND_EXACT_SESSION
)
279 /* Otherwise look for prefix. */
281 RB_FOREACH(s_loop
, sessions
, &sessions
) {
282 if (strncmp(session
, s_loop
->name
, strlen(session
)) == 0) {
293 /* Then as a pattern. */
295 RB_FOREACH(s_loop
, sessions
, &sessions
) {
296 if (fnmatch(session
, s_loop
->name
, 0) == 0) {
310 /* Find window from string. Fills in s, wl, w. */
312 cmd_find_get_window(struct cmd_find_state
*fs
, const char *window
, int only
)
314 log_debug("%s: %s", __func__
, window
);
316 /* Check for window ids starting with @. */
317 if (*window
== '@') {
318 fs
->w
= window_find_by_id_str(window
);
321 return (cmd_find_best_session_with_window(fs
));
324 /* Not a window id, so use the current session. */
325 fs
->s
= fs
->current
->s
;
327 /* We now only need to find the winlink in this session. */
328 if (cmd_find_get_window_with_session(fs
, window
) == 0)
331 /* Otherwise try as a session itself. */
332 if (!only
&& cmd_find_get_session(fs
, window
) == 0) {
333 fs
->wl
= fs
->s
->curw
;
334 fs
->w
= fs
->wl
->window
;
335 if (~fs
->flags
& CMD_FIND_WINDOW_INDEX
)
336 fs
->idx
= fs
->wl
->idx
;
344 * Find window from string, assuming it is in given session. Needs s, fills in
348 cmd_find_get_window_with_session(struct cmd_find_state
*fs
, const char *window
)
355 log_debug("%s: %s", __func__
, window
);
356 exact
= (fs
->flags
& CMD_FIND_EXACT_WINDOW
);
359 * Start with the current window as the default. So if only an index is
360 * found, the window will be the current.
362 fs
->wl
= fs
->s
->curw
;
363 fs
->w
= fs
->wl
->window
;
365 /* Check for window ids starting with @. */
366 if (*window
== '@') {
367 fs
->w
= window_find_by_id_str(window
);
368 if (fs
->w
== NULL
|| !session_has(fs
->s
, fs
->w
))
370 return (cmd_find_best_winlink_with_window(fs
));
373 /* Try as an offset. */
374 if (!exact
&& (window
[0] == '+' || window
[0] == '-')) {
375 if (window
[1] != '\0')
376 n
= strtonum(window
+ 1, 1, INT_MAX
, NULL
);
380 if (fs
->flags
& CMD_FIND_WINDOW_INDEX
) {
381 if (window
[0] == '+') {
382 if (INT_MAX
- s
->curw
->idx
< n
)
384 fs
->idx
= s
->curw
->idx
+ n
;
386 if (n
> s
->curw
->idx
)
388 fs
->idx
= s
->curw
->idx
- n
;
392 if (window
[0] == '+')
393 fs
->wl
= winlink_next_by_number(s
->curw
, s
, n
);
395 fs
->wl
= winlink_previous_by_number(s
->curw
, s
, n
);
396 if (fs
->wl
!= NULL
) {
397 fs
->idx
= fs
->wl
->idx
;
398 fs
->w
= fs
->wl
->window
;
403 /* Try special characters. */
405 if (strcmp(window
, "!") == 0) {
406 fs
->wl
= TAILQ_FIRST(&fs
->s
->lastw
);
409 fs
->idx
= fs
->wl
->idx
;
410 fs
->w
= fs
->wl
->window
;
412 } else if (strcmp(window
, "^") == 0) {
413 fs
->wl
= RB_MIN(winlinks
, &fs
->s
->windows
);
416 fs
->idx
= fs
->wl
->idx
;
417 fs
->w
= fs
->wl
->window
;
419 } else if (strcmp(window
, "$") == 0) {
420 fs
->wl
= RB_MAX(winlinks
, &fs
->s
->windows
);
423 fs
->idx
= fs
->wl
->idx
;
424 fs
->w
= fs
->wl
->window
;
429 /* First see if this is a valid window index in this session. */
430 if (window
[0] != '+' && window
[0] != '-') {
431 idx
= strtonum(window
, 0, INT_MAX
, &errstr
);
432 if (errstr
== NULL
) {
433 fs
->wl
= winlink_find_by_index(&fs
->s
->windows
, idx
);
434 if (fs
->wl
!= NULL
) {
435 fs
->idx
= fs
->wl
->idx
;
436 fs
->w
= fs
->wl
->window
;
439 if (fs
->flags
& CMD_FIND_WINDOW_INDEX
) {
446 /* Look for exact matches, error if more than one. */
448 RB_FOREACH(wl
, winlinks
, &fs
->s
->windows
) {
449 if (strcmp(window
, wl
->window
->name
) == 0) {
455 if (fs
->wl
!= NULL
) {
456 fs
->idx
= fs
->wl
->idx
;
457 fs
->w
= fs
->wl
->window
;
461 /* Stop now if exact only. */
465 /* Try as the start of a window name, error if multiple. */
467 RB_FOREACH(wl
, winlinks
, &fs
->s
->windows
) {
468 if (strncmp(window
, wl
->window
->name
, strlen(window
)) == 0) {
474 if (fs
->wl
!= NULL
) {
475 fs
->idx
= fs
->wl
->idx
;
476 fs
->w
= fs
->wl
->window
;
480 /* Now look for pattern matches, again error if multiple. */
482 RB_FOREACH(wl
, winlinks
, &fs
->s
->windows
) {
483 if (fnmatch(window
, wl
->window
->name
, 0) == 0) {
489 if (fs
->wl
!= NULL
) {
490 fs
->idx
= fs
->wl
->idx
;
491 fs
->w
= fs
->wl
->window
;
498 /* Find pane from string. Fills in s, wl, w, wp. */
500 cmd_find_get_pane(struct cmd_find_state
*fs
, const char *pane
, int only
)
502 log_debug("%s: %s", __func__
, pane
);
504 /* Check for pane ids starting with %. */
506 fs
->wp
= window_pane_find_by_id_str(pane
);
509 fs
->w
= fs
->wp
->window
;
510 return (cmd_find_best_session_with_window(fs
));
513 /* Not a pane id, so try the current session and window. */
514 fs
->s
= fs
->current
->s
;
515 fs
->wl
= fs
->current
->wl
;
516 fs
->idx
= fs
->current
->idx
;
517 fs
->w
= fs
->current
->w
;
519 /* We now only need to find the pane in this window. */
520 if (cmd_find_get_pane_with_window(fs
, pane
) == 0)
523 /* Otherwise try as a window itself (this will also try as session). */
524 if (!only
&& cmd_find_get_window(fs
, pane
, 0) == 0) {
525 fs
->wp
= fs
->w
->active
;
533 * Find pane from string, assuming it is in given session. Needs s, fills in wl
537 cmd_find_get_pane_with_session(struct cmd_find_state
*fs
, const char *pane
)
539 log_debug("%s: %s", __func__
, pane
);
541 /* Check for pane ids starting with %. */
543 fs
->wp
= window_pane_find_by_id_str(pane
);
546 fs
->w
= fs
->wp
->window
;
547 return (cmd_find_best_winlink_with_window(fs
));
550 /* Otherwise use the current window. */
551 fs
->wl
= fs
->s
->curw
;
552 fs
->idx
= fs
->wl
->idx
;
553 fs
->w
= fs
->wl
->window
;
555 /* Now we just need to look up the pane. */
556 return (cmd_find_get_pane_with_window(fs
, pane
));
560 * Find pane from string, assuming it is in the given window. Needs w, fills in
564 cmd_find_get_pane_with_window(struct cmd_find_state
*fs
, const char *pane
)
568 struct window_pane
*wp
;
571 log_debug("%s: %s", __func__
, pane
);
573 /* Check for pane ids starting with %. */
575 fs
->wp
= window_pane_find_by_id_str(pane
);
578 if (fs
->wp
->window
!= fs
->w
)
583 /* Try special characters. */
584 if (strcmp(pane
, "!") == 0) {
585 fs
->wp
= TAILQ_FIRST(&fs
->w
->last_panes
);
589 } else if (strcmp(pane
, "{up-of}") == 0) {
590 fs
->wp
= window_pane_find_up(fs
->w
->active
);
594 } else if (strcmp(pane
, "{down-of}") == 0) {
595 fs
->wp
= window_pane_find_down(fs
->w
->active
);
599 } else if (strcmp(pane
, "{left-of}") == 0) {
600 fs
->wp
= window_pane_find_left(fs
->w
->active
);
604 } else if (strcmp(pane
, "{right-of}") == 0) {
605 fs
->wp
= window_pane_find_right(fs
->w
->active
);
611 /* Try as an offset. */
612 if (pane
[0] == '+' || pane
[0] == '-') {
614 n
= strtonum(pane
+ 1, 1, INT_MAX
, NULL
);
619 fs
->wp
= window_pane_next_by_number(fs
->w
, wp
, n
);
621 fs
->wp
= window_pane_previous_by_number(fs
->w
, wp
, n
);
626 /* Get pane by index. */
627 idx
= strtonum(pane
, 0, INT_MAX
, &errstr
);
628 if (errstr
== NULL
) {
629 fs
->wp
= window_pane_at_index(fs
->w
, idx
);
634 /* Try as a description. */
635 fs
->wp
= window_find_string(fs
->w
, pane
);
644 cmd_find_clear_state(struct cmd_find_state
*fs
, int flags
)
646 memset(fs
, 0, sizeof *fs
);
653 /* Check if state is empty. */
655 cmd_find_empty_state(struct cmd_find_state
*fs
)
657 if (fs
->s
== NULL
&& fs
->wl
== NULL
&& fs
->w
== NULL
&& fs
->wp
== NULL
)
662 /* Check if a state if valid. */
664 cmd_find_valid_state(struct cmd_find_state
*fs
)
668 if (fs
->s
== NULL
|| fs
->wl
== NULL
|| fs
->w
== NULL
|| fs
->wp
== NULL
)
671 if (!session_alive(fs
->s
))
674 RB_FOREACH(wl
, winlinks
, &fs
->s
->windows
) {
675 if (wl
->window
== fs
->w
&& wl
== fs
->wl
)
681 if (fs
->w
!= fs
->wl
->window
)
684 return (window_has_pane(fs
->w
, fs
->wp
));
689 cmd_find_copy_state(struct cmd_find_state
*dst
, struct cmd_find_state
*src
)
698 /* Log the result. */
700 cmd_find_log_state(const char *prefix
, struct cmd_find_state
*fs
)
703 log_debug("%s: s=$%u %s", prefix
, fs
->s
->id
, fs
->s
->name
);
705 log_debug("%s: s=none", prefix
);
706 if (fs
->wl
!= NULL
) {
707 log_debug("%s: wl=%u %d w=@%u %s", prefix
, fs
->wl
->idx
,
708 fs
->wl
->window
== fs
->w
, fs
->w
->id
, fs
->w
->name
);
710 log_debug("%s: wl=none", prefix
);
712 log_debug("%s: wp=%%%u", prefix
, fs
->wp
->id
);
714 log_debug("%s: wp=none", prefix
);
716 log_debug("%s: idx=%d", prefix
, fs
->idx
);
718 log_debug("%s: idx=none", prefix
);
721 /* Find state from a session. */
723 cmd_find_from_session(struct cmd_find_state
*fs
, struct session
*s
, int flags
)
725 cmd_find_clear_state(fs
, flags
);
728 fs
->wl
= fs
->s
->curw
;
729 fs
->w
= fs
->wl
->window
;
730 fs
->wp
= fs
->w
->active
;
732 cmd_find_log_state(__func__
, fs
);
735 /* Find state from a winlink. */
737 cmd_find_from_winlink(struct cmd_find_state
*fs
, struct winlink
*wl
, int flags
)
739 cmd_find_clear_state(fs
, flags
);
744 fs
->wp
= wl
->window
->active
;
746 cmd_find_log_state(__func__
, fs
);
749 /* Find state from a session and window. */
751 cmd_find_from_session_window(struct cmd_find_state
*fs
, struct session
*s
,
752 struct window
*w
, int flags
)
754 cmd_find_clear_state(fs
, flags
);
758 if (cmd_find_best_winlink_with_window(fs
) != 0) {
759 cmd_find_clear_state(fs
, flags
);
762 fs
->wp
= fs
->w
->active
;
764 cmd_find_log_state(__func__
, fs
);
768 /* Find state from a window. */
770 cmd_find_from_window(struct cmd_find_state
*fs
, struct window
*w
, int flags
)
772 cmd_find_clear_state(fs
, flags
);
775 if (cmd_find_best_session_with_window(fs
) != 0) {
776 cmd_find_clear_state(fs
, flags
);
779 if (cmd_find_best_winlink_with_window(fs
) != 0) {
780 cmd_find_clear_state(fs
, flags
);
783 fs
->wp
= fs
->w
->active
;
785 cmd_find_log_state(__func__
, fs
);
789 /* Find state from a winlink and pane. */
791 cmd_find_from_winlink_pane(struct cmd_find_state
*fs
, struct winlink
*wl
,
792 struct window_pane
*wp
, int flags
)
794 cmd_find_clear_state(fs
, flags
);
798 fs
->idx
= fs
->wl
->idx
;
799 fs
->w
= fs
->wl
->window
;
802 cmd_find_log_state(__func__
, fs
);
805 /* Find state from a pane. */
807 cmd_find_from_pane(struct cmd_find_state
*fs
, struct window_pane
*wp
, int flags
)
809 if (cmd_find_from_window(fs
, wp
->window
, flags
) != 0)
813 cmd_find_log_state(__func__
, fs
);
817 /* Find state from nothing. */
819 cmd_find_from_nothing(struct cmd_find_state
*fs
, int flags
)
821 cmd_find_clear_state(fs
, flags
);
823 fs
->s
= cmd_find_best_session(NULL
, 0, flags
);
825 cmd_find_clear_state(fs
, flags
);
828 fs
->wl
= fs
->s
->curw
;
829 fs
->idx
= fs
->wl
->idx
;
830 fs
->w
= fs
->wl
->window
;
831 fs
->wp
= fs
->w
->active
;
833 cmd_find_log_state(__func__
, fs
);
837 /* Find state from mouse. */
839 cmd_find_from_mouse(struct cmd_find_state
*fs
, struct mouse_event
*m
, int flags
)
841 cmd_find_clear_state(fs
, flags
);
846 fs
->wp
= cmd_mouse_pane(m
, &fs
->s
, &fs
->wl
);
847 if (fs
->wp
== NULL
) {
848 cmd_find_clear_state(fs
, flags
);
851 fs
->w
= fs
->wl
->window
;
853 cmd_find_log_state(__func__
, fs
);
857 /* Find state from client. */
859 cmd_find_from_client(struct cmd_find_state
*fs
, struct client
*c
, int flags
)
861 struct window_pane
*wp
;
863 /* If no client, treat as from nothing. */
865 return (cmd_find_from_nothing(fs
, flags
));
867 /* If this is an attached client, all done. */
868 if (c
->session
!= NULL
) {
869 cmd_find_clear_state(fs
, flags
);
871 fs
->wp
= server_client_get_pane(c
);
872 if (fs
->wp
== NULL
) {
873 cmd_find_from_session(fs
, c
->session
, flags
);
877 fs
->wl
= fs
->s
->curw
;
878 fs
->w
= fs
->wl
->window
;
880 cmd_find_log_state(__func__
, fs
);
883 cmd_find_clear_state(fs
, flags
);
886 * If this is an unattached client running in a pane, we can use that
887 * to limit the list of sessions to those containing that pane.
889 wp
= cmd_find_inside_pane(c
);
894 * Don't have a session, or it doesn't have this pane. Try all
898 if (cmd_find_best_session_with_window(fs
) != 0) {
900 * The window may have been destroyed but the pane
901 * still on all_window_panes due to something else
902 * holding a reference.
906 fs
->wl
= fs
->s
->curw
;
907 fs
->w
= fs
->wl
->window
;
908 fs
->wp
= fs
->w
->active
; /* use active pane */
910 cmd_find_log_state(__func__
, fs
);
914 /* We can't find the pane so need to guess. */
915 return (cmd_find_from_nothing(fs
, flags
));
919 * Split target into pieces and resolve for the given type. Fills in the given
920 * state. Returns 0 on success or -1 on error.
923 cmd_find_target(struct cmd_find_state
*fs
, struct cmdq_item
*item
,
924 const char *target
, enum cmd_find_type type
, int flags
)
926 struct mouse_event
*m
;
927 struct cmd_find_state current
;
928 char *colon
, *period
, *copy
= NULL
, tmp
[256];
929 const char *session
, *window
, *pane
, *s
;
930 int window_only
= 0, pane_only
= 0;
932 /* Can fail flag implies quiet. */
933 if (flags
& CMD_FIND_CANFAIL
)
934 flags
|= CMD_FIND_QUIET
;
936 /* Log the arguments. */
937 if (type
== CMD_FIND_PANE
)
939 else if (type
== CMD_FIND_WINDOW
)
941 else if (type
== CMD_FIND_SESSION
)
946 if (flags
& CMD_FIND_PREFER_UNATTACHED
)
947 strlcat(tmp
, "PREFER_UNATTACHED,", sizeof tmp
);
948 if (flags
& CMD_FIND_QUIET
)
949 strlcat(tmp
, "QUIET,", sizeof tmp
);
950 if (flags
& CMD_FIND_WINDOW_INDEX
)
951 strlcat(tmp
, "WINDOW_INDEX,", sizeof tmp
);
952 if (flags
& CMD_FIND_DEFAULT_MARKED
)
953 strlcat(tmp
, "DEFAULT_MARKED,", sizeof tmp
);
954 if (flags
& CMD_FIND_EXACT_SESSION
)
955 strlcat(tmp
, "EXACT_SESSION,", sizeof tmp
);
956 if (flags
& CMD_FIND_EXACT_WINDOW
)
957 strlcat(tmp
, "EXACT_WINDOW,", sizeof tmp
);
958 if (flags
& CMD_FIND_CANFAIL
)
959 strlcat(tmp
, "CANFAIL,", sizeof tmp
);
961 tmp
[strlen(tmp
) - 1] = '\0';
963 strlcat(tmp
, "NONE", sizeof tmp
);
964 log_debug("%s: target %s, type %s, item %p, flags %s", __func__
,
965 target
== NULL
? "none" : target
, s
, item
, tmp
);
967 /* Clear new state. */
968 cmd_find_clear_state(fs
, flags
);
970 /* Find current state. */
971 if (server_check_marked() && (flags
& CMD_FIND_DEFAULT_MARKED
)) {
972 fs
->current
= &marked_pane
;
973 log_debug("%s: current is marked pane", __func__
);
974 } else if (cmd_find_valid_state(cmdq_get_current(item
))) {
975 fs
->current
= cmdq_get_current(item
);
976 log_debug("%s: current is from queue", __func__
);
977 } else if (cmd_find_from_client(¤t
, cmdq_get_client(item
),
979 fs
->current
= ¤t
;
980 log_debug("%s: current is from client", __func__
);
982 if (~flags
& CMD_FIND_QUIET
)
983 cmdq_error(item
, "no current target");
986 if (!cmd_find_valid_state(fs
->current
))
987 fatalx("invalid current find state");
989 /* An empty or NULL target is the current. */
990 if (target
== NULL
|| *target
== '\0')
993 /* Mouse target is a plain = or {mouse}. */
994 if (strcmp(target
, "=") == 0 || strcmp(target
, "{mouse}") == 0) {
995 m
= &cmdq_get_event(item
)->m
;
998 fs
->wp
= cmd_mouse_pane(m
, &fs
->s
, &fs
->wl
);
999 if (fs
->wp
!= NULL
) {
1000 fs
->w
= fs
->wl
->window
;
1004 case CMD_FIND_WINDOW
:
1005 case CMD_FIND_SESSION
:
1006 fs
->wl
= cmd_mouse_window(m
, &fs
->s
);
1007 if (fs
->wl
== NULL
&& fs
->s
!= NULL
)
1008 fs
->wl
= fs
->s
->curw
;
1009 if (fs
->wl
!= NULL
) {
1010 fs
->w
= fs
->wl
->window
;
1011 fs
->wp
= fs
->w
->active
;
1015 if (fs
->wp
== NULL
) {
1016 if (~flags
& CMD_FIND_QUIET
)
1017 cmdq_error(item
, "no mouse target");
1023 /* Marked target is a plain ~ or {marked}. */
1024 if (strcmp(target
, "~") == 0 || strcmp(target
, "{marked}") == 0) {
1025 if (!server_check_marked()) {
1026 if (~flags
& CMD_FIND_QUIET
)
1027 cmdq_error(item
, "no marked target");
1030 cmd_find_copy_state(fs
, &marked_pane
);
1034 /* Find separators if they exist. */
1035 copy
= xstrdup(target
);
1036 colon
= strchr(copy
, ':');
1040 period
= strchr(copy
, '.');
1042 period
= strchr(colon
, '.');
1046 /* Set session, window and pane parts. */
1047 session
= window
= pane
= NULL
;
1048 if (colon
!= NULL
&& period
!= NULL
) {
1054 } else if (colon
!= NULL
&& period
== NULL
) {
1058 } else if (colon
== NULL
&& period
!= NULL
) {
1065 else if (*copy
== '@')
1067 else if (*copy
== '%')
1071 case CMD_FIND_SESSION
:
1074 case CMD_FIND_WINDOW
:
1084 /* Set exact match flags. */
1085 if (session
!= NULL
&& *session
== '=') {
1087 fs
->flags
|= CMD_FIND_EXACT_SESSION
;
1089 if (window
!= NULL
&& *window
== '=') {
1091 fs
->flags
|= CMD_FIND_EXACT_WINDOW
;
1094 /* Empty is the same as NULL. */
1095 if (session
!= NULL
&& *session
== '\0')
1097 if (window
!= NULL
&& *window
== '\0')
1099 if (pane
!= NULL
&& *pane
== '\0')
1102 /* Map though conversion table. */
1103 if (session
!= NULL
)
1104 session
= cmd_find_map_table(cmd_find_session_table
, session
);
1106 window
= cmd_find_map_table(cmd_find_window_table
, window
);
1108 pane
= cmd_find_map_table(cmd_find_pane_table
, pane
);
1110 if (session
!= NULL
|| window
!= NULL
|| pane
!= NULL
) {
1111 log_debug("%s: target %s is %s%s%s%s%s%s",
1113 session
== NULL
? "" : "session ",
1114 session
== NULL
? "" : session
,
1115 window
== NULL
? "" : "window ",
1116 window
== NULL
? "" : window
,
1117 pane
== NULL
? "" : "pane ",
1118 pane
== NULL
? "" : pane
);
1121 /* No pane is allowed if want an index. */
1122 if (pane
!= NULL
&& (flags
& CMD_FIND_WINDOW_INDEX
)) {
1123 if (~flags
& CMD_FIND_QUIET
)
1124 cmdq_error(item
, "can't specify pane here");
1128 /* If the session isn't NULL, look it up. */
1129 if (session
!= NULL
) {
1130 /* This will fill in session. */
1131 if (cmd_find_get_session(fs
, session
) != 0)
1134 /* If window and pane are NULL, use that session's current. */
1135 if (window
== NULL
&& pane
== NULL
) {
1136 fs
->wl
= fs
->s
->curw
;
1138 fs
->w
= fs
->wl
->window
;
1139 fs
->wp
= fs
->w
->active
;
1143 /* If window is present but pane not, find window in session. */
1144 if (window
!= NULL
&& pane
== NULL
) {
1145 /* This will fill in winlink and window. */
1146 if (cmd_find_get_window_with_session(fs
, window
) != 0)
1148 if (fs
->wl
!= NULL
) /* can be NULL if index only */
1149 fs
->wp
= fs
->wl
->window
->active
;
1153 /* If pane is present but window not, find pane. */
1154 if (window
== NULL
&& pane
!= NULL
) {
1155 /* This will fill in winlink and window and pane. */
1156 if (cmd_find_get_pane_with_session(fs
, pane
) != 0)
1162 * If window and pane are present, find both in session. This
1163 * will fill in winlink and window.
1165 if (cmd_find_get_window_with_session(fs
, window
) != 0)
1167 /* This will fill in pane. */
1168 if (cmd_find_get_pane_with_window(fs
, pane
) != 0)
1173 /* No session. If window and pane, try them. */
1174 if (window
!= NULL
&& pane
!= NULL
) {
1175 /* This will fill in session, winlink and window. */
1176 if (cmd_find_get_window(fs
, window
, window_only
) != 0)
1178 /* This will fill in pane. */
1179 if (cmd_find_get_pane_with_window(fs
, pane
) != 0)
1184 /* If just window is present, try it. */
1185 if (window
!= NULL
&& pane
== NULL
) {
1186 /* This will fill in session, winlink and window. */
1187 if (cmd_find_get_window(fs
, window
, window_only
) != 0)
1189 if (fs
->wl
!= NULL
) /* can be NULL if index only */
1190 fs
->wp
= fs
->wl
->window
->active
;
1194 /* If just pane is present, try it. */
1195 if (window
== NULL
&& pane
!= NULL
) {
1196 /* This will fill in session, winlink, window and pane. */
1197 if (cmd_find_get_pane(fs
, pane
, pane_only
) != 0)
1203 /* Use the current session. */
1204 cmd_find_copy_state(fs
, fs
->current
);
1205 if (flags
& CMD_FIND_WINDOW_INDEX
)
1211 log_debug("%s: error", __func__
);
1214 if (flags
& CMD_FIND_CANFAIL
)
1220 cmd_find_log_state(__func__
, fs
);
1226 if (~flags
& CMD_FIND_QUIET
)
1227 cmdq_error(item
, "can't find session: %s", session
);
1231 if (~flags
& CMD_FIND_QUIET
)
1232 cmdq_error(item
, "can't find window: %s", window
);
1236 if (~flags
& CMD_FIND_QUIET
)
1237 cmdq_error(item
, "can't find pane: %s", pane
);
1241 /* Find the current client. */
1242 static struct client
*
1243 cmd_find_current_client(struct cmdq_item
*item
, int quiet
)
1245 struct client
*c
= NULL
, *found
;
1247 struct window_pane
*wp
;
1248 struct cmd_find_state fs
;
1251 c
= cmdq_get_client(item
);
1252 if (c
!= NULL
&& c
->session
!= NULL
)
1256 if (c
!= NULL
&& (wp
= cmd_find_inside_pane(c
)) != NULL
) {
1257 cmd_find_clear_state(&fs
, CMD_FIND_QUIET
);
1259 if (cmd_find_best_session_with_window(&fs
) == 0)
1260 found
= cmd_find_best_client(fs
.s
);
1262 s
= cmd_find_best_session(NULL
, 0, CMD_FIND_QUIET
);
1264 found
= cmd_find_best_client(s
);
1266 if (found
== NULL
&& item
!= NULL
&& !quiet
)
1267 cmdq_error(item
, "no current client");
1268 log_debug("%s: no target, return %p", __func__
, found
);
1272 /* Find the target client or report an error and return NULL. */
1274 cmd_find_client(struct cmdq_item
*item
, const char *target
, int quiet
)
1280 /* A NULL argument means the current client. */
1282 return (cmd_find_current_client(item
, quiet
));
1283 copy
= xstrdup(target
);
1285 /* Trim a single trailing colon if any. */
1286 size
= strlen(copy
);
1287 if (size
!= 0 && copy
[size
- 1] == ':')
1288 copy
[size
- 1] = '\0';
1290 /* Check name and path of each client. */
1291 TAILQ_FOREACH(c
, &clients
, entry
) {
1292 if (c
->session
== NULL
)
1294 if (strcmp(copy
, c
->name
) == 0)
1297 if (*c
->ttyname
== '\0')
1299 if (strcmp(copy
, c
->ttyname
) == 0)
1301 if (strncmp(c
->ttyname
, _PATH_DEV
, (sizeof _PATH_DEV
) - 1) != 0)
1303 if (strcmp(copy
, c
->ttyname
+ (sizeof _PATH_DEV
) - 1) == 0)
1307 /* If no client found, report an error. */
1308 if (c
== NULL
&& !quiet
)
1309 cmdq_error(item
, "can't find client: %s", copy
);
1312 log_debug("%s: target %s, return %p", __func__
, target
, c
);