mirror of
https://github.com/tmux/tmux.git
synced 2024-12-04 19:58:48 +00:00
Merge branch 'obsd-master'
Conflicts: Makefile tmux.1
This commit is contained in:
commit
94a8ef1cae
@ -80,6 +80,7 @@ dist_tmux_SOURCES = \
|
||||
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 \
|
||||
|
18
cfg.c
18
cfg.c
@ -26,12 +26,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)
|
||||
@ -113,10 +113,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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
1114
cmd-find.c
Normal file
1114
cmd-find.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -92,7 +92,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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -146,6 +146,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)
|
||||
@ -158,7 +159,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);
|
||||
|
||||
@ -193,8 +193,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)
|
||||
|
937
cmd.c
937
cmd.c
@ -115,24 +115,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)
|
||||
{
|
||||
@ -331,183 +313,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,
|
||||
@ -559,7 +364,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;
|
||||
@ -576,745 +382,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)
|
||||
|
@ -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;
|
||||
|
||||
|
182
tmux.1
182
tmux.1
@ -362,6 +362,7 @@ 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
|
||||
.Xr pty 7
|
||||
@ -371,27 +372,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.
|
||||
@ -404,12 +413,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
|
||||
@ -419,53 +445,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 -
|
||||
@ -474,19 +497,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
|
||||
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
|
||||
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
|
||||
.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
|
||||
@ -3148,7 +3186,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
|
||||
|
25
tmux.h
25
tmux.h
@ -1738,8 +1738,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);
|
||||
@ -1754,16 +1765,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;
|
||||
|
92
window.c
92
window.c
@ -48,8 +48,6 @@
|
||||
* it reaches zero.
|
||||
*/
|
||||
|
||||
ARRAY_DECL(window_pane_list, struct window_pane *);
|
||||
|
||||
/* Global window list. */
|
||||
struct windows windows;
|
||||
|
||||
@ -63,7 +61,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);
|
||||
|
||||
@ -255,7 +253,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;
|
||||
@ -1163,17 +1161,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;
|
||||
}
|
||||
@ -1187,14 +1185,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)
|
||||
@ -1217,12 +1216,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);
|
||||
}
|
||||
|
||||
@ -1230,14 +1231,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)
|
||||
@ -1260,12 +1262,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);
|
||||
}
|
||||
|
||||
@ -1273,14 +1277,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)
|
||||
@ -1303,12 +1308,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);
|
||||
}
|
||||
|
||||
@ -1316,14 +1323,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)
|
||||
@ -1346,12 +1354,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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user