diff --git a/cmd-list-panes.c b/cmd-list-panes.c index 8533b624..863182ff 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -1,4 +1,4 @@ -/* $Id: cmd-list-panes.c,v 1.7 2011-01-07 14:45:34 tcunha Exp $ */ +/* $Id: cmd-list-panes.c,v 1.8 2011-04-06 22:16:33 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -64,8 +64,8 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) } size += gd->hsize * sizeof *gd->linedata; - ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]%s%s", - n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, + ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes] %%%u%s%s", + n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, wp->id, wp == wp->window->active ? " (active)" : "", wp->fd == -1 ? " (dead)" : ""); n++; diff --git a/cmd.c b/cmd.c index ef781aa0..2241454c 100644 --- a/cmd.c +++ b/cmd.c @@ -1,4 +1,4 @@ -/* $Id: cmd.c,v 1.149 2011-02-14 23:11:33 tcunha Exp $ */ +/* $Id: cmd.c,v 1.150 2011-04-06 22:16:33 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -117,9 +117,12 @@ struct client *cmd_lookup_client(const char *); struct session *cmd_lookup_session(const char *, int *); struct winlink *cmd_lookup_window(struct session *, const char *, int *); int cmd_lookup_index(struct session *, const char *, int *); +struct window_pane *cmd_lookup_paneid(const char *); +struct session *cmd_pane_session(struct cmd_ctx *, + struct window_pane *, 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 *); +struct window_pane *cmd_find_pane_offset(const char *, struct winlink *); int cmd_pack_argv(int argc, char **argv, char *buf, size_t len) @@ -638,21 +641,78 @@ cmd_lookup_index(struct session *s, const char *name, int *ambiguous) return (-1); } +/* + * Lookup pane id. An initial % means a pane id. sp must already point to the + * current session. + */ +struct window_pane * +cmd_lookup_paneid(const char *arg) +{ + const char *errstr; + u_int paneid; + + if (*arg != '%') + return (NULL); + + paneid = strtonum(arg + 1, 0, UINT_MAX, &errstr); + if (errstr != NULL) + return (NULL); + return (window_pane_find_by_id(paneid)); +} + +/* Find session and winlink for pane. */ +struct session * +cmd_pane_session(struct cmd_ctx *ctx, struct window_pane *wp, + struct winlink **wlp) +{ + struct session *s; + struct sessionslist ss; + struct winlink *wl; + + /* If this pane is in the current session, return that winlink. */ + s = cmd_current_session(ctx); + if (s != NULL) { + wl = winlink_find_by_window(&s->windows, wp->window); + if (wl != NULL) { + if (wlp != NULL) + *wlp = wl; + return (s); + } + } + + /* Otherwise choose from all sessions with this pane. */ + ARRAY_INIT(&ss); + RB_FOREACH(s, sessions, &sessions) { + if (winlink_find_by_window(&s->windows, wp->window) != NULL) + ARRAY_ADD(&ss, s); + } + s = cmd_choose_session_list(&ss); + ARRAY_FREE(&ss); + if (wlp != NULL) + *wlp = winlink_find_by_window(&s->windows, wp->window); + return (s); +} + /* Find the target session or report an error and return NULL. */ struct session * cmd_find_session(struct cmd_ctx *ctx, const char *arg) { - struct session *s; - struct client *c; - char *tmparg; - size_t arglen; - int ambiguous; + struct session *s; + struct window_pane *wp; + struct client *c; + char *tmparg; + size_t arglen; + int ambiguous; /* A NULL argument means the current session. */ if (arg == NULL) return (cmd_current_session(ctx)); tmparg = xstrdup(arg); + /* Lookup as pane id. */ + if ((wp = cmd_lookup_paneid(arg)) != NULL) + return (cmd_pane_session(ctx, wp, NULL)); + /* Trim a single trailing colon if any. */ arglen = strlen(tmparg); if (arglen != 0 && tmparg[arglen - 1] == ':') @@ -681,11 +741,12 @@ cmd_find_session(struct cmd_ctx *ctx, const char *arg) struct winlink * cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) { - struct session *s; - struct winlink *wl; - const char *winptr; - char *sessptr = NULL; - int ambiguous = 0; + struct session *s; + struct winlink *wl; + struct window_pane *wp; + const char *winptr; + char *sessptr = NULL; + int ambiguous = 0; /* * Find the current session. There must always be a current session, if @@ -703,6 +764,14 @@ cmd_find_window(struct cmd_ctx *ctx, const char *arg, struct session **sp) return (s->curw); } + /* Lookup as pane id. */ + if ((wp = cmd_lookup_paneid(arg)) != NULL) { + s = cmd_pane_session(ctx, wp, &wl); + if (sp != NULL) + *sp = s; + return (wl); + } + /* Time to look at the argument. If it is empty, that is an error. */ if (*arg == '\0') goto not_found; @@ -997,6 +1066,14 @@ cmd_find_pane(struct cmd_ctx *ctx, return (s->curw); } + /* Lookup as pane id. */ + if ((*wpp = cmd_lookup_paneid(arg)) != NULL) { + s = cmd_pane_session(ctx, *wpp, &wl); + if (sp != NULL) + *sp = s; + return (wl); + } + /* Look for a separating period. */ if ((period = strrchr(arg, '.')) == NULL) goto no_period; diff --git a/server.c b/server.c index eb68bd05..93d9314b 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* $Id: server.c,v 1.253 2011-02-15 15:12:28 tcunha Exp $ */ +/* $Id: server.c,v 1.254 2011-04-06 22:16:33 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -142,6 +142,7 @@ server_start(void) log_debug("server started, pid %ld", (long) getpid()); ARRAY_INIT(&windows); + RB_INIT(&all_window_panes); ARRAY_INIT(&clients); ARRAY_INIT(&dead_clients); RB_INIT(&sessions); diff --git a/tmux.1 b/tmux.1 index a8e7737a..4beb152d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,4 +1,4 @@ -.\" $Id: tmux.1,v 1.296 2011-03-19 23:27:35 tcunha Exp $ +.\" $Id: tmux.1,v 1.297 2011-04-06 22:16:33 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -453,6 +453,17 @@ select-window -t:+2 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 +.Nm +server and 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. +.Pp .Ar shell-command arguments are .Xr sh 1 diff --git a/tmux.h b/tmux.h index 99bef196..9e4c681f 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.612 2011-03-19 23:30:37 tcunha Exp $ */ +/* $Id: tmux.h,v 1.613 2011-04-06 22:16:33 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -775,6 +775,8 @@ struct window_mode { /* Child window structure. */ struct window_pane { + u_int id; + struct window *window; struct layout_cell *layout_cell; @@ -817,8 +819,10 @@ struct window_pane { void *modedata; TAILQ_ENTRY(window_pane) entry; + RB_ENTRY(window_pane) tree_entry; }; TAILQ_HEAD(window_panes, window_pane); +RB_HEAD(window_pane_tree, window_pane); /* Window structure. */ struct window { @@ -1821,8 +1825,11 @@ int screen_check_selection(struct screen *, u_int, u_int); /* window.c */ extern struct windows windows; +extern struct window_pane_tree all_window_panes; int winlink_cmp(struct winlink *, struct winlink *); RB_PROTOTYPE(winlinks, winlink, entry, winlink_cmp); +int window_pane_cmp(struct window_pane *, struct window_pane *); +RB_PROTOTYPE(window_pane_tree, window_pane, tree_entry, window_pane_cmp); struct winlink *winlink_find_by_index(struct winlinks *, int); struct winlink *winlink_find_by_window(struct winlinks *, struct window *); int winlink_next_index(struct winlinks *, int); @@ -1857,6 +1864,7 @@ struct window_pane *window_pane_previous_by_number(struct window *, u_int window_pane_index(struct window *, struct window_pane *); u_int window_count_panes(struct window *); void window_destroy_panes(struct window *); +struct window_pane *window_pane_find_by_id(u_int); struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); void window_pane_destroy(struct window_pane *); int window_pane_spawn(struct window_pane *, const char *, diff --git a/window.c b/window.c index a2449080..2a458c41 100644 --- a/window.c +++ b/window.c @@ -1,4 +1,4 @@ -/* $Id: window.c,v 1.145 2011-02-15 15:09:52 tcunha Exp $ */ +/* $Id: window.c,v 1.146 2011-04-06 22:16:33 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -53,6 +53,10 @@ /* Global window list. */ struct windows windows; +/* Global panes tree. */ +struct window_pane_tree all_window_panes; +u_int next_window_pane; + void window_pane_read_callback(struct bufferevent *, void *); void window_pane_error_callback(struct bufferevent *, short, void *); @@ -64,6 +68,14 @@ winlink_cmp(struct winlink *wl1, struct winlink *wl2) return (wl1->idx - wl2->idx); } +RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_cmp); + +int +window_pane_cmp(struct window_pane *wp1, struct window_pane *wp2) +{ + return (wp1->id - wp2->id); +} + struct winlink * winlink_find_by_window(struct winlinks *wwl, struct window *w) { @@ -492,6 +504,16 @@ window_printable_flags(struct session *s, struct winlink *wl) return (xstrdup(flags)); } +/* Find pane in global tree by id. */ +struct window_pane * +window_pane_find_by_id(u_int id) +{ + struct window_pane wp; + + wp.id = id; + return (RB_FIND(window_pane_tree, &all_window_panes, &wp)); +} + struct window_pane * window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) { @@ -500,6 +522,9 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp = xcalloc(1, sizeof *wp); wp->window = w; + wp->id = next_window_pane++; + RB_INSERT(window_pane_tree, &all_window_panes, wp); + wp->cmd = NULL; wp->shell = NULL; wp->cwd = NULL; @@ -552,6 +577,8 @@ window_pane_destroy(struct window_pane *wp) bufferevent_free(wp->pipe_event); } + RB_REMOVE(window_pane_tree, &all_window_panes, wp); + if (wp->cwd != NULL) xfree(wp->cwd); if (wp->shell != NULL) @@ -566,7 +593,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, const char *cwd, struct environ *env, struct termios *tio, char **cause) { struct winsize ws; - char *argv0; + char *argv0, paneid[16]; const char *ptr; struct termios tio2; @@ -613,6 +640,8 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, closefrom(STDERR_FILENO + 1); + xsnprintf(paneid, sizeof paneid, "%%%u", wp->id); + environ_set(env, "TMUX_PANE", paneid); environ_push(env); clear_signals(1);