From dc0d34e13792ff14b5c02fac01af013dfe111c83 Mon Sep 17 00:00:00 2001 From: jmc Date: Thu, 4 Jun 2015 20:34:22 +0000 Subject: [PATCH 01/12] tweak SYNOPSIS and usage(); --- tmux.1 | 2 +- tmux.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux.1 b/tmux.1 index e479afbe..fbf0e180 100644 --- a/tmux.1 +++ b/tmux.1 @@ -23,7 +23,7 @@ .Sh SYNOPSIS .Nm tmux .Bk -words -.Op Fl 2lCuv +.Op Fl 2Cluv .Op Fl c Ar shell-command .Op Fl f Ar file .Op Fl L Ar socket-name diff --git a/tmux.c b/tmux.c index 77a39248..878180a7 100644 --- a/tmux.c +++ b/tmux.c @@ -58,7 +58,7 @@ __dead void usage(void) { fprintf(stderr, - "usage: %s [-2lquv] [-c shell-command] [-f file] [-L socket-name]\n" + "usage: %s [-2Cluv] [-c shell-command] [-f file] [-L socket-name]\n" " [-S socket-path] [command [flags]]\n", __progname); exit(1); From 6b2129696fbefe44d0adce1f2a11b4ae477cd07e Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 4 Jun 2015 23:27:51 +0000 Subject: [PATCH 02/12] Move the nested check from client to server and compare the client tty name to all the pane pty names instead of comparing socket paths. This means that "new -d" will work without unsetting $TMUX. --- client.c | 16 +--------------- cmd-attach-session.c | 7 ++++++- cmd-new-session.c | 19 ++++++++++++------- server-client.c | 21 +++++++++++++++++++++ tmux.h | 4 ++-- 5 files changed, 42 insertions(+), 25 deletions(-) diff --git a/client.c b/client.c index e2ffa546..48109613 100644 --- a/client.c +++ b/client.c @@ -222,7 +222,7 @@ client_main(int argc, char **argv, int flags) cmdflags = CMD_STARTSERVER; } else if (argc == 0) { msg = MSG_COMMAND; - cmdflags = CMD_STARTSERVER|CMD_CANTNEST; + cmdflags = CMD_STARTSERVER; } else { msg = MSG_COMMAND; @@ -240,24 +240,10 @@ client_main(int argc, char **argv, int flags) TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { if (cmd->entry->flags & CMD_STARTSERVER) cmdflags |= CMD_STARTSERVER; - if (cmd->entry->flags & CMD_CANTNEST) - cmdflags |= CMD_CANTNEST; } cmd_list_free(cmdlist); } - /* - * Check if this could be a nested session, if the command can't nest: - * if the socket path matches $TMUX, this is probably the same server. - */ - if (shell_cmd == NULL && environ_path != NULL && - (cmdflags & CMD_CANTNEST) && - strcmp(socket_path, environ_path) == 0) { - fprintf(stderr, "sessions should be nested with care, " - "unset $TMUX to force\n"); - return (1); - } - /* Set process title, log and signals now this is the client. */ setproctitle("client (%s)", socket_path); logfile("client"); diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 46d568b4..f889019c 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -36,7 +36,7 @@ const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", "c:drt:", 0, 0, "[-dr] [-c working-directory] " CMD_TARGET_SESSION_USAGE, - CMD_CANTNEST|CMD_STARTSERVER, + CMD_STARTSERVER, cmd_attach_session_exec }; @@ -81,6 +81,11 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, if (cmdq->client == NULL) return (CMD_RETURN_NORMAL); + if (server_client_check_nested(cmdq->client)) { + cmdq_error(cmdq, "sessions should be nested with care, " + "unset $TMUX to force"); + return (CMD_RETURN_ERROR); + } if (wl != NULL) { if (wp != NULL) diff --git a/cmd-new-session.c b/cmd-new-session.c index 9c767489..0fb849e2 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -41,7 +41,7 @@ const struct cmd_entry cmd_new_session_entry = { "[-AdDP] [-c start-directory] [-F format] [-n window-name] " "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] " "[-y height] [command]", - CMD_STARTSERVER|CMD_CANTNEST, + CMD_STARTSERVER, cmd_new_session_exec }; @@ -145,15 +145,20 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) } /* - * Save the termios settings, part of which is used for new windows in - * this session. + * If this is a new client, check for nesting and save the termios + * settings (part of which is used for new windows in this session). * - * This is read again with tcgetattr() rather than using tty.tio as if - * detached, tty_open won't be called. Because of this, it must be done - * before opening the terminal as that calls tcsetattr() to prepare for - * tmux taking over. + * tcgetattr() is used rather than using tty.tio since if the client is + * detached, tty_open won't be called. It must be done before opening + * the terminal as that calls tcsetattr() to prepare for tmux taking + * over. */ if (!detached && !already_attached && c->tty.fd != -1) { + if (server_client_check_nested(cmdq->client)) { + cmdq_error(cmdq, "sessions should be nested with care, " + "unset $TMUX to force"); + return (CMD_RETURN_ERROR); + } if (tcgetattr(c->tty.fd, &tio) != 0) fatal("tcgetattr failed"); tiop = &tio; diff --git a/server-client.c b/server-client.c index 36408e91..01c8b313 100644 --- a/server-client.c +++ b/server-client.c @@ -46,6 +46,27 @@ void server_client_msg_command(struct client *, struct imsg *); void server_client_msg_identify(struct client *, struct imsg *); void server_client_msg_shell(struct client *); +/* Check if this client is inside this server. */ +int +server_client_check_nested(struct client *c) +{ + struct environ_entry *envent; + struct window_pane *wp; + + if (c->tty.path == NULL) + return (0); + + envent = environ_find(&c->environ, "TMUX"); + if (envent == NULL || *envent->value == '\0') + return (0); + + RB_FOREACH(wp, window_pane_tree, &all_window_panes) { + if (strcmp(wp->tty, c->tty.path) == 0) + return (1); + } + return (0); +} + /* Set client key table. */ void server_client_key_table(struct client *c, const char *name) diff --git a/tmux.h b/tmux.h index ae1682af..8406955b 100644 --- a/tmux.h +++ b/tmux.h @@ -1374,8 +1374,7 @@ struct cmd_entry { const char *usage; #define CMD_STARTSERVER 0x1 -#define CMD_CANTNEST 0x2 -#define CMD_READONLY 0x4 +#define CMD_READONLY 0x2 int flags; enum cmd_retval (*exec)(struct cmd *, struct cmd_q *); @@ -1868,6 +1867,7 @@ void server_update_socket(void); void server_add_accept(int); /* server-client.c */ +int server_client_check_nested(struct client *); void server_client_handle_key(struct client *, int); void server_client_create(int); int server_client_open(struct client *, char **); From 4219939c10980051a6d272853c96b6e1931639b1 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 5 Jun 2015 08:14:16 +0000 Subject: [PATCH 03/12] Make it so that if a window or session target is prefixed with an =, only an exact name or index match is accepted, no special character, prefix match, or fnmatch. --- cmd-find.c | 92 ++++++++++++++++++++++++++++++++------------------ key-bindings.c | 20 +++++------ tmux.1 | 11 ++++++ 3 files changed, 80 insertions(+), 43 deletions(-) diff --git a/cmd-find.c b/cmd-find.c index 2b862f95..7b4d4c3e 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -30,6 +30,8 @@ #define CMD_FIND_QUIET 0x2 #define CMD_FIND_WINDOW_INDEX 0x4 #define CMD_FIND_DEFAULT_MARKED 0x8 +#define CMD_FIND_EXACT_SESSION 0x10 +#define CMD_FIND_EXACT_WINDOW 0x20 enum cmd_find_type { CMD_FIND_PANE, @@ -381,6 +383,10 @@ cmd_find_get_session(struct cmd_find_state *fs, const char *session) if (fs->s != NULL) return (0); + /* Stop now if exact only. */ + if (fs->flags & CMD_FIND_EXACT_SESSION) + return (-1); + /* Otherwise look for prefix. */ s = NULL; RB_FOREACH(s_loop, sessions, &sessions) { @@ -455,10 +461,11 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window) { struct winlink *wl; const char *errstr; - int idx, n; + int idx, n, exact; struct session *s; log_debug("%s: %s", __func__, window); + exact = (fs->flags & CMD_FIND_EXACT_WINDOW); /* Check for window ids starting with @. */ if (*window == '@') { @@ -469,7 +476,7 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window) } /* Try as an offset. */ - if (window[0] == '+' || window[0] == '-') { + if (!exact && window[0] == '+' || window[0] == '-') { if (window[1] != '\0') n = strtonum(window + 1, 1, INT_MAX, NULL); else @@ -499,40 +506,44 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window) } /* 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); + if (!exact) { + 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); + if (window[0] != '+' && window[0] != '-') { + 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); + } } } @@ -551,6 +562,11 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window) return (0); } + + /* Stop now if exact only. */ + if (exact) + return (-1); + /* Try as the start of a window name, error if multiple. */ fs->wl = NULL; RB_FOREACH(wl, winlinks, &fs->s->windows) { @@ -868,6 +884,16 @@ cmd_find_target(struct cmd_q *cmdq, const char *target, enum cmd_find_type type, } } + /* Set exact match flags. */ + if (session != NULL && *session == '=') { + session++; + fs.flags |= CMD_FIND_EXACT_SESSION; + } + if (window != NULL && *window == '=') { + window++; + fs.flags |= CMD_FIND_EXACT_WINDOW; + } + /* Empty is the same as NULL. */ if (session != NULL && *session == '\0') session = NULL; diff --git a/key-bindings.c b/key-bindings.c index ab4751f9..3dc3a054 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -161,16 +161,16 @@ key_bindings_init(void) "bind , command-prompt -I'#W' \"rename-window '%%'\"", "bind - delete-buffer", "bind . command-prompt \"move-window -t '%%'\"", - "bind 0 select-window -t:0", - "bind 1 select-window -t:1", - "bind 2 select-window -t:2", - "bind 3 select-window -t:3", - "bind 4 select-window -t:4", - "bind 5 select-window -t:5", - "bind 6 select-window -t:6", - "bind 7 select-window -t:7", - "bind 8 select-window -t:8", - "bind 9 select-window -t:9", + "bind 0 select-window -t:=0", + "bind 1 select-window -t:=1", + "bind 2 select-window -t:=2", + "bind 3 select-window -t:=3", + "bind 4 select-window -t:=4", + "bind 5 select-window -t:=5", + "bind 6 select-window -t:=6", + "bind 7 select-window -t:=7", + "bind 8 select-window -t:=8", + "bind 9 select-window -t:=9", "bind : command-prompt", "bind \\; last-pane", "bind = choose-buffer", diff --git a/tmux.1 b/tmux.1 index fbf0e180..7ad33530 100644 --- a/tmux.1 +++ b/tmux.1 @@ -404,6 +404,14 @@ An pattern which is matched against the session name. .El .Pp +If the session name is prefixed with a +.Ql = : , +only an exact match is accepted (so +.Ql =mysess +will only match exactly +.Ql mysess , +not +.Ql mysession ) . 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 @@ -440,6 +448,9 @@ As an pattern matched against the window name. .El .Pp +Like sessions, a +.Ql = +prefix will do an exact match only. An empty window name specifies the next unused index if appropriate (for example the .Ic new-window From 2f586905fc7dc4a3f65a1bca1ad94e28ffc3508d Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 5 Jun 2015 09:09:08 +0000 Subject: [PATCH 04/12] Fix a warning. --- cmd-find.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-find.c b/cmd-find.c index 7b4d4c3e..5e0b1dbb 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -476,7 +476,7 @@ cmd_find_get_window_with_session(struct cmd_find_state *fs, const char *window) } /* Try as an offset. */ - if (!exact && window[0] == '+' || window[0] == '-') { + if (!exact && (window[0] == '+' || window[0] == '-')) { if (window[1] != '\0') n = strtonum(window + 1, 1, INT_MAX, NULL); else From b0782df8a64f744b7c067e6f918ce5217ea09e57 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 5 Jun 2015 15:10:13 +0000 Subject: [PATCH 05/12] Do not use the key variable uninitialized (in a debug log statement), reported by jungleboogie0 at gmail dot com. --- tty-keys.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tty-keys.c b/tty-keys.c index 1df22d4c..75e06526 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -501,6 +501,7 @@ tty_keys_next(struct tty *tty) case -1: /* no, or not valid */ break; case -2: /* yes, but we don't care. */ + key = KEYC_MOUSE; goto discard_key; case 1: /* partial */ goto partial_key; From 8c93b768e4864be330c3d6a7962892135224f0f4 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 5 Jun 2015 18:01:12 +0000 Subject: [PATCH 06/12] Instead of putting dead clients on a list and checking it every loop, use event_once to queue a callback to deal with them. Also dead clients with references would never actually be freed because the wrap-up functions (the callback for stdin, or status_prompt_clear) would never be called. So call them in server_client_lost. --- cmd-confirm-before.c | 2 +- cmd-load-buffer.c | 2 +- server-client.c | 37 ++++++++++++++++++++++++++++++++++--- server.c | 11 ----------- tmux.h | 1 + 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 5e4816ed..e6104574 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -117,7 +117,7 @@ cmd_confirm_before_free(void *data) struct cmd_confirm_before_data *cdata = data; struct client *c = cdata->client; - c->references--; + server_client_deref(c); free(cdata->cmd); free(cdata); diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 3a26db39..8f653929 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -132,7 +132,7 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data) return; c->stdin_callback = NULL; - c->references--; + server_client_deref(c); if (c->flags & CLIENT_DEAD) return; diff --git a/server-client.c b/server-client.c index 01c8b313..b10c1e13 100644 --- a/server-client.c +++ b/server-client.c @@ -31,6 +31,7 @@ #include "tmux.h" void server_client_key_table(struct client *, const char *); +void server_client_free(int, short, void *); void server_client_check_focus(struct window_pane *); void server_client_check_resize(struct window_pane *); int server_client_check_mouse(struct client *); @@ -85,7 +86,7 @@ server_client_create(int fd) setblocking(fd, 0); c = xcalloc(1, sizeof *c); - c->references = 0; + c->references = 1; imsg_init(&c->ibuf, fd); server_update_event(c); @@ -161,6 +162,14 @@ server_client_lost(struct client *c) { struct message_entry *msg, *msg1; + c->flags |= CLIENT_DEAD; + + status_prompt_clear(c); + status_message_clear(c); + + if (c->stdin_callback != NULL) + c->stdin_callback(c, 1, c->stdin_callback_data); + TAILQ_REMOVE(&clients, c, entry); log_debug("lost client %d", c->ibuf.fd); @@ -213,8 +222,7 @@ server_client_lost(struct client *c) if (event_initialized(&c->event)) event_del(&c->event); - TAILQ_INSERT_TAIL(&dead_clients, c, entry); - c->flags |= CLIENT_DEAD; + server_client_deref(c); server_add_accept(0); /* may be more file descriptors now */ @@ -223,6 +231,29 @@ server_client_lost(struct client *c) server_update_socket(); } +/* Remove reference from a client. */ +void +server_client_deref(struct client *c) +{ + log_debug("deref client %d (%d references)", c->ibuf.fd, c->references); + + c->references--; + if (c->references == 0) + event_once(-1, EV_TIMEOUT, server_client_free, c, NULL); +} + +/* Free dead client. */ +void +server_client_free(unused int fd, unused short events, void *arg) +{ + struct client *c = arg; + + log_debug("free client %d (%d references)", c->ibuf.fd, c->references); + + if (c->references == 0) + free(c); +} + /* Process a single client event. */ void server_client_callback(int fd, short events, void *data) diff --git a/server.c b/server.c index 52fdb0c3..cc5a63f6 100644 --- a/server.c +++ b/server.c @@ -41,9 +41,7 @@ * Main server functions. */ -/* Client list. */ struct clients clients; -struct clients dead_clients; int server_fd; int server_shutdown; @@ -205,7 +203,6 @@ server_start(int lockfd, char *lockfile) RB_INIT(&windows); RB_INIT(&all_window_panes); TAILQ_INIT(&clients); - TAILQ_INIT(&dead_clients); RB_INIT(&sessions); RB_INIT(&dead_sessions); TAILQ_INIT(&session_groups); @@ -325,7 +322,6 @@ void server_clean_dead(void) { struct session *s, *s1; - struct client *c, *c1; RB_FOREACH_SAFE(s, sessions, &dead_sessions, s1) { if (s->references != 0) @@ -334,13 +330,6 @@ server_clean_dead(void) free(s->name); free(s); } - - TAILQ_FOREACH_SAFE(c, &dead_clients, entry, c1) { - if (c->references != 0) - continue; - TAILQ_REMOVE(&dead_clients, c, entry); - free(c); - } } /* Update socket execute permissions based on whether sessions are attached. */ diff --git a/tmux.h b/tmux.h index 8406955b..fa36fe6f 100644 --- a/tmux.h +++ b/tmux.h @@ -1871,6 +1871,7 @@ int server_client_check_nested(struct client *); void server_client_handle_key(struct client *, int); void server_client_create(int); int server_client_open(struct client *, char **); +void server_client_deref(struct client *); void server_client_lost(struct client *); void server_client_callback(int, short, void *); void server_client_status_timer(void); From 10e90ae01f53a67a1b7c3a2c498cefb73c6a23b4 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 5 Jun 2015 18:06:30 +0000 Subject: [PATCH 07/12] Change deref to the more sensible unref, and add a couple I missed before. --- cfg.c | 2 +- cmd-confirm-before.c | 2 +- cmd-load-buffer.c | 2 +- notify.c | 2 +- server-client.c | 6 +++--- tmux.h | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cfg.c b/cfg.c index ff43976e..37474094 100644 --- a/cfg.c +++ b/cfg.c @@ -108,7 +108,7 @@ cfg_default_done(unused struct cmd_q *cmdq) */ if (!TAILQ_EMPTY(&cfg_client->cmdq->queue)) cmdq_continue(cfg_client->cmdq); - cfg_client->references--; + server_client_unref(cfg_client); cfg_client = NULL; } } diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index e6104574..248515cd 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -117,7 +117,7 @@ cmd_confirm_before_free(void *data) struct cmd_confirm_before_data *cdata = data; struct client *c = cdata->client; - server_client_deref(c); + server_client_unref(c); free(cdata->cmd); free(cdata); diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c index 8f653929..897807d0 100644 --- a/cmd-load-buffer.c +++ b/cmd-load-buffer.c @@ -132,7 +132,7 @@ cmd_load_buffer_callback(struct client *c, int closed, void *data) return; c->stdin_callback = NULL; - server_client_deref(c); + server_client_unref(c); if (c->flags & CLIENT_DEAD) return; diff --git a/notify.c b/notify.c index 19bf17e8..8dfbd6ba 100644 --- a/notify.c +++ b/notify.c @@ -121,7 +121,7 @@ notify_drain(void) } if (ne->client != NULL) - ne->client->references--; + server_client_unref(ne->client); if (ne->session != NULL) ne->session->references--; if (ne->window != NULL) diff --git a/server-client.c b/server-client.c index b10c1e13..8739b5ab 100644 --- a/server-client.c +++ b/server-client.c @@ -222,7 +222,7 @@ server_client_lost(struct client *c) if (event_initialized(&c->event)) event_del(&c->event); - server_client_deref(c); + server_client_unref(c); server_add_accept(0); /* may be more file descriptors now */ @@ -233,9 +233,9 @@ server_client_lost(struct client *c) /* Remove reference from a client. */ void -server_client_deref(struct client *c) +server_client_unref(struct client *c) { - log_debug("deref client %d (%d references)", c->ibuf.fd, c->references); + log_debug("unref client %d (%d references)", c->ibuf.fd, c->references); c->references--; if (c->references == 0) diff --git a/tmux.h b/tmux.h index fa36fe6f..7068eb44 100644 --- a/tmux.h +++ b/tmux.h @@ -1871,7 +1871,7 @@ int server_client_check_nested(struct client *); void server_client_handle_key(struct client *, int); void server_client_create(int); int server_client_open(struct client *, char **); -void server_client_deref(struct client *); +void server_client_unref(struct client *); void server_client_lost(struct client *); void server_client_callback(int, short, void *); void server_client_status_timer(void); From 641a9cd3f591b0ace3ae9947ebe6ab889b641eed Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 5 Jun 2015 18:18:32 +0000 Subject: [PATCH 08/12] Similarly, for sessions use a callback to free rather than checking every loop. --- notify.c | 2 +- server.c | 19 ------------------- session.c | 31 +++++++++++++++++++++++++++---- tmux.h | 2 +- window-choose.c | 6 +++--- 5 files changed, 32 insertions(+), 28 deletions(-) diff --git a/notify.c b/notify.c index 8dfbd6ba..b51a5e59 100644 --- a/notify.c +++ b/notify.c @@ -123,7 +123,7 @@ notify_drain(void) if (ne->client != NULL) server_client_unref(ne->client); if (ne->session != NULL) - ne->session->references--; + session_unref(ne->session); if (ne->window != NULL) window_remove_ref(ne->window); diff --git a/server.c b/server.c index cc5a63f6..001a404c 100644 --- a/server.c +++ b/server.c @@ -58,7 +58,6 @@ int server_create_socket(void); void server_loop(void); int server_should_shutdown(void); void server_send_shutdown(void); -void server_clean_dead(void); void server_accept_callback(int, short, void *); void server_signal_callback(int, short, void *); void server_child_signal(void); @@ -204,7 +203,6 @@ server_start(int lockfd, char *lockfile) RB_INIT(&all_window_panes); TAILQ_INIT(&clients); RB_INIT(&sessions); - RB_INIT(&dead_sessions); TAILQ_INIT(&session_groups); mode_key_init_trees(); key_bindings_init(); @@ -264,8 +262,6 @@ server_loop(void) server_window_loop(); server_client_loop(); - - server_clean_dead(); } } @@ -317,21 +313,6 @@ server_send_shutdown(void) session_destroy(s); } -/* Free dead, unreferenced clients and sessions. */ -void -server_clean_dead(void) -{ - struct session *s, *s1; - - RB_FOREACH_SAFE(s, sessions, &dead_sessions, s1) { - if (s->references != 0) - continue; - RB_REMOVE(sessions, &dead_sessions, s); - free(s->name); - free(s); - } -} - /* Update socket execute permissions based on whether sessions are attached. */ void server_update_socket(void) diff --git a/session.c b/session.c index 907bdee9..5061083a 100644 --- a/session.c +++ b/session.c @@ -27,12 +27,12 @@ #include "tmux.h" -/* Global session list. */ struct sessions sessions; -struct sessions dead_sessions; u_int next_session_id; struct session_groups session_groups; +void session_free(int, short, void *); + struct winlink *session_next_alert(struct winlink *); struct winlink *session_previous_alert(struct winlink *); @@ -109,7 +109,7 @@ session_create(const char *name, int argc, char **argv, const char *path, struct winlink *wl; s = xmalloc(sizeof *s); - s->references = 0; + s->references = 1; s->flags = 0; if (gettimeofday(&s->creation_time, NULL) != 0) @@ -164,6 +164,29 @@ session_create(const char *name, int argc, char **argv, const char *path, return (s); } +/* Remove a reference from a session. */ +void +session_unref(struct session *s) +{ + log_debug("session %s has %d references", s->name, s->references); + + s->references--; + if (s->references == 0) + event_once(-1, EV_TIMEOUT, session_free, s, NULL); +} + +/* Free session. */ +void +session_free(unused int fd, unused short events, void *arg) +{ + struct session *s = arg; + + log_debug("sesson %s freed (%d references)", s->name, s->references); + + if (s->references == 0) + free(s); +} + /* Destroy a session. */ void session_destroy(struct session *s) @@ -191,7 +214,7 @@ session_destroy(struct session *s) close(s->cwd); - RB_INSERT(sessions, &dead_sessions, s); + session_unref(s); } /* Check a session name is valid: not empty and no colons or periods. */ diff --git a/tmux.h b/tmux.h index 7068eb44..699ee81e 100644 --- a/tmux.h +++ b/tmux.h @@ -2259,7 +2259,6 @@ void control_notify_session_close(struct session *); /* session.c */ extern struct sessions sessions; -extern struct sessions dead_sessions; extern struct session_groups session_groups; int session_cmp(struct session *, struct session *); RB_PROTOTYPE(sessions, session, entry, session_cmp); @@ -2271,6 +2270,7 @@ struct session *session_create(const char *, int, char **, const char *, int, struct environ *, struct termios *, int, u_int, u_int, char **); void session_destroy(struct session *); +void session_unref(struct session *); int session_check_name(const char *); void session_update_activity(struct session *); struct session *session_next_session(struct session *); diff --git a/window-choose.c b/window-choose.c index 2af56e23..c71fea3d 100644 --- a/window-choose.c +++ b/window-choose.c @@ -209,11 +209,11 @@ window_choose_data_create(int type, struct client *c, struct session *s) void window_choose_data_free(struct window_choose_data *wcd) { - wcd->start_client->references--; - wcd->start_session->references--; + server_client_unref(wcd->start_client); + session_unref(wcd->start_session); if (wcd->tree_session != NULL) - wcd->tree_session->references--; + session_unref(wcd->tree_session); free(wcd->ft_template); format_free(wcd->ft); From 1cb073d48efa74b2e593a2beb8f56fbda6f9076a Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 5 Jun 2015 22:01:17 +0000 Subject: [PATCH 09/12] Use fixed colour tables rather than generated and do a quick search for exact match before doing the distance comparison. --- colour.c | 377 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 292 insertions(+), 85 deletions(-) diff --git a/colour.c b/colour.c index 82f8533a..5929e982 100644 --- a/colour.c +++ b/colour.c @@ -29,91 +29,306 @@ * of the 256 colour palette. */ -/* An RGB colour. */ struct colour_rgb { + u_char i; u_char r; u_char g; u_char b; }; -/* 256 colour RGB table, generated on first use. */ -struct colour_rgb *colour_rgb_256; +const struct colour_rgb colour_from_256[] = { + { 0, 0x00, 0x00, 0x00 }, { 1, 0x00, 0x00, 0x5f }, + { 2, 0x00, 0x00, 0x87 }, { 3, 0x00, 0x00, 0xaf }, + { 4, 0x00, 0x00, 0xd7 }, { 5, 0x00, 0x00, 0xff }, + { 6, 0x00, 0x5f, 0x00 }, { 7, 0x00, 0x5f, 0x5f }, + { 8, 0x00, 0x5f, 0x87 }, { 9, 0x00, 0x5f, 0xaf }, + { 10, 0x00, 0x5f, 0xd7 }, { 11, 0x00, 0x5f, 0xff }, + { 12, 0x00, 0x87, 0x00 }, { 13, 0x00, 0x87, 0x5f }, + { 14, 0x00, 0x87, 0x87 }, { 15, 0x00, 0x87, 0xaf }, + { 16, 0x00, 0x87, 0xd7 }, { 17, 0x00, 0x87, 0xff }, + { 18, 0x00, 0xaf, 0x00 }, { 19, 0x00, 0xaf, 0x5f }, + { 20, 0x00, 0xaf, 0x87 }, { 21, 0x00, 0xaf, 0xaf }, + { 22, 0x00, 0xaf, 0xd7 }, { 23, 0x00, 0xaf, 0xff }, + { 24, 0x00, 0xd7, 0x00 }, { 25, 0x00, 0xd7, 0x5f }, + { 26, 0x00, 0xd7, 0x87 }, { 27, 0x00, 0xd7, 0xaf }, + { 28, 0x00, 0xd7, 0xd7 }, { 29, 0x00, 0xd7, 0xff }, + { 30, 0x00, 0xff, 0x00 }, { 31, 0x00, 0xff, 0x5f }, + { 32, 0x00, 0xff, 0x87 }, { 33, 0x00, 0xff, 0xaf }, + { 34, 0x00, 0xff, 0xd7 }, { 35, 0x00, 0xff, 0xff }, + { 36, 0x5f, 0x00, 0x00 }, { 37, 0x5f, 0x00, 0x5f }, + { 38, 0x5f, 0x00, 0x87 }, { 39, 0x5f, 0x00, 0xaf }, + { 40, 0x5f, 0x00, 0xd7 }, { 41, 0x5f, 0x00, 0xff }, + { 42, 0x5f, 0x5f, 0x00 }, { 43, 0x5f, 0x5f, 0x5f }, + { 44, 0x5f, 0x5f, 0x87 }, { 45, 0x5f, 0x5f, 0xaf }, + { 46, 0x5f, 0x5f, 0xd7 }, { 47, 0x5f, 0x5f, 0xff }, + { 48, 0x5f, 0x87, 0x00 }, { 49, 0x5f, 0x87, 0x5f }, + { 50, 0x5f, 0x87, 0x87 }, { 51, 0x5f, 0x87, 0xaf }, + { 52, 0x5f, 0x87, 0xd7 }, { 53, 0x5f, 0x87, 0xff }, + { 54, 0x5f, 0xaf, 0x00 }, { 55, 0x5f, 0xaf, 0x5f }, + { 56, 0x5f, 0xaf, 0x87 }, { 57, 0x5f, 0xaf, 0xaf }, + { 58, 0x5f, 0xaf, 0xd7 }, { 59, 0x5f, 0xaf, 0xff }, + { 60, 0x5f, 0xd7, 0x00 }, { 61, 0x5f, 0xd7, 0x5f }, + { 62, 0x5f, 0xd7, 0x87 }, { 63, 0x5f, 0xd7, 0xaf }, + { 64, 0x5f, 0xd7, 0xd7 }, { 65, 0x5f, 0xd7, 0xff }, + { 66, 0x5f, 0xff, 0x00 }, { 67, 0x5f, 0xff, 0x5f }, + { 68, 0x5f, 0xff, 0x87 }, { 69, 0x5f, 0xff, 0xaf }, + { 70, 0x5f, 0xff, 0xd7 }, { 71, 0x5f, 0xff, 0xff }, + { 72, 0x87, 0x00, 0x00 }, { 73, 0x87, 0x00, 0x5f }, + { 74, 0x87, 0x00, 0x87 }, { 75, 0x87, 0x00, 0xaf }, + { 76, 0x87, 0x00, 0xd7 }, { 77, 0x87, 0x00, 0xff }, + { 78, 0x87, 0x5f, 0x00 }, { 79, 0x87, 0x5f, 0x5f }, + { 80, 0x87, 0x5f, 0x87 }, { 81, 0x87, 0x5f, 0xaf }, + { 82, 0x87, 0x5f, 0xd7 }, { 83, 0x87, 0x5f, 0xff }, + { 84, 0x87, 0x87, 0x00 }, { 85, 0x87, 0x87, 0x5f }, + { 86, 0x87, 0x87, 0x87 }, { 87, 0x87, 0x87, 0xaf }, + { 88, 0x87, 0x87, 0xd7 }, { 89, 0x87, 0x87, 0xff }, + { 90, 0x87, 0xaf, 0x00 }, { 91, 0x87, 0xaf, 0x5f }, + { 92, 0x87, 0xaf, 0x87 }, { 93, 0x87, 0xaf, 0xaf }, + { 94, 0x87, 0xaf, 0xd7 }, { 95, 0x87, 0xaf, 0xff }, + { 96, 0x87, 0xd7, 0x00 }, { 97, 0x87, 0xd7, 0x5f }, + { 98, 0x87, 0xd7, 0x87 }, { 99, 0x87, 0xd7, 0xaf }, + { 100, 0x87, 0xd7, 0xd7 }, { 101, 0x87, 0xd7, 0xff }, + { 102, 0x87, 0xff, 0x00 }, { 103, 0x87, 0xff, 0x5f }, + { 104, 0x87, 0xff, 0x87 }, { 105, 0x87, 0xff, 0xaf }, + { 106, 0x87, 0xff, 0xd7 }, { 107, 0x87, 0xff, 0xff }, + { 108, 0xaf, 0x00, 0x00 }, { 109, 0xaf, 0x00, 0x5f }, + { 110, 0xaf, 0x00, 0x87 }, { 111, 0xaf, 0x00, 0xaf }, + { 112, 0xaf, 0x00, 0xd7 }, { 113, 0xaf, 0x00, 0xff }, + { 114, 0xaf, 0x5f, 0x00 }, { 115, 0xaf, 0x5f, 0x5f }, + { 116, 0xaf, 0x5f, 0x87 }, { 117, 0xaf, 0x5f, 0xaf }, + { 118, 0xaf, 0x5f, 0xd7 }, { 119, 0xaf, 0x5f, 0xff }, + { 120, 0xaf, 0x87, 0x00 }, { 121, 0xaf, 0x87, 0x5f }, + { 122, 0xaf, 0x87, 0x87 }, { 123, 0xaf, 0x87, 0xaf }, + { 124, 0xaf, 0x87, 0xd7 }, { 125, 0xaf, 0x87, 0xff }, + { 126, 0xaf, 0xaf, 0x00 }, { 127, 0xaf, 0xaf, 0x5f }, + { 128, 0xaf, 0xaf, 0x87 }, { 129, 0xaf, 0xaf, 0xaf }, + { 130, 0xaf, 0xaf, 0xd7 }, { 131, 0xaf, 0xaf, 0xff }, + { 132, 0xaf, 0xd7, 0x00 }, { 133, 0xaf, 0xd7, 0x5f }, + { 134, 0xaf, 0xd7, 0x87 }, { 135, 0xaf, 0xd7, 0xaf }, + { 136, 0xaf, 0xd7, 0xd7 }, { 137, 0xaf, 0xd7, 0xff }, + { 138, 0xaf, 0xff, 0x00 }, { 139, 0xaf, 0xff, 0x5f }, + { 140, 0xaf, 0xff, 0x87 }, { 141, 0xaf, 0xff, 0xaf }, + { 142, 0xaf, 0xff, 0xd7 }, { 143, 0xaf, 0xff, 0xff }, + { 144, 0xd7, 0x00, 0x00 }, { 145, 0xd7, 0x00, 0x5f }, + { 146, 0xd7, 0x00, 0x87 }, { 147, 0xd7, 0x00, 0xaf }, + { 148, 0xd7, 0x00, 0xd7 }, { 149, 0xd7, 0x00, 0xff }, + { 150, 0xd7, 0x5f, 0x00 }, { 151, 0xd7, 0x5f, 0x5f }, + { 152, 0xd7, 0x5f, 0x87 }, { 153, 0xd7, 0x5f, 0xaf }, + { 154, 0xd7, 0x5f, 0xd7 }, { 155, 0xd7, 0x5f, 0xff }, + { 156, 0xd7, 0x87, 0x00 }, { 157, 0xd7, 0x87, 0x5f }, + { 158, 0xd7, 0x87, 0x87 }, { 159, 0xd7, 0x87, 0xaf }, + { 160, 0xd7, 0x87, 0xd7 }, { 161, 0xd7, 0x87, 0xff }, + { 162, 0xd7, 0xaf, 0x00 }, { 163, 0xd7, 0xaf, 0x5f }, + { 164, 0xd7, 0xaf, 0x87 }, { 165, 0xd7, 0xaf, 0xaf }, + { 166, 0xd7, 0xaf, 0xd7 }, { 167, 0xd7, 0xaf, 0xff }, + { 168, 0xd7, 0xd7, 0x00 }, { 169, 0xd7, 0xd7, 0x5f }, + { 170, 0xd7, 0xd7, 0x87 }, { 171, 0xd7, 0xd7, 0xaf }, + { 172, 0xd7, 0xd7, 0xd7 }, { 173, 0xd7, 0xd7, 0xff }, + { 174, 0xd7, 0xff, 0x00 }, { 175, 0xd7, 0xff, 0x5f }, + { 176, 0xd7, 0xff, 0x87 }, { 177, 0xd7, 0xff, 0xaf }, + { 178, 0xd7, 0xff, 0xd7 }, { 179, 0xd7, 0xff, 0xff }, + { 180, 0xff, 0x00, 0x00 }, { 181, 0xff, 0x00, 0x5f }, + { 182, 0xff, 0x00, 0x87 }, { 183, 0xff, 0x00, 0xaf }, + { 184, 0xff, 0x00, 0xd7 }, { 185, 0xff, 0x00, 0xff }, + { 186, 0xff, 0x5f, 0x00 }, { 187, 0xff, 0x5f, 0x5f }, + { 188, 0xff, 0x5f, 0x87 }, { 189, 0xff, 0x5f, 0xaf }, + { 190, 0xff, 0x5f, 0xd7 }, { 191, 0xff, 0x5f, 0xff }, + { 192, 0xff, 0x87, 0x00 }, { 193, 0xff, 0x87, 0x5f }, + { 194, 0xff, 0x87, 0x87 }, { 195, 0xff, 0x87, 0xaf }, + { 196, 0xff, 0x87, 0xd7 }, { 197, 0xff, 0x87, 0xff }, + { 198, 0xff, 0xaf, 0x00 }, { 199, 0xff, 0xaf, 0x5f }, + { 200, 0xff, 0xaf, 0x87 }, { 201, 0xff, 0xaf, 0xaf }, + { 202, 0xff, 0xaf, 0xd7 }, { 203, 0xff, 0xaf, 0xff }, + { 204, 0xff, 0xd7, 0x00 }, { 205, 0xff, 0xd7, 0x5f }, + { 206, 0xff, 0xd7, 0x87 }, { 207, 0xff, 0xd7, 0xaf }, + { 208, 0xff, 0xd7, 0xd7 }, { 209, 0xff, 0xd7, 0xff }, + { 210, 0xff, 0xff, 0x00 }, { 211, 0xff, 0xff, 0x5f }, + { 212, 0xff, 0xff, 0x87 }, { 213, 0xff, 0xff, 0xaf }, + { 214, 0xff, 0xff, 0xd7 }, { 215, 0xff, 0xff, 0xff }, + { 216, 0x08, 0x08, 0x08 }, { 217, 0x12, 0x12, 0x12 }, + { 218, 0x1c, 0x1c, 0x1c }, { 219, 0x26, 0x26, 0x26 }, + { 220, 0x30, 0x30, 0x30 }, { 221, 0x3a, 0x3a, 0x3a }, + { 222, 0x44, 0x44, 0x44 }, { 223, 0x4e, 0x4e, 0x4e }, + { 224, 0x58, 0x58, 0x58 }, { 225, 0x62, 0x62, 0x62 }, + { 226, 0x6c, 0x6c, 0x6c }, { 227, 0x76, 0x76, 0x76 }, + { 228, 0x80, 0x80, 0x80 }, { 229, 0x8a, 0x8a, 0x8a }, + { 230, 0x94, 0x94, 0x94 }, { 231, 0x9e, 0x9e, 0x9e }, + { 232, 0xa8, 0xa8, 0xa8 }, { 233, 0xb2, 0xb2, 0xb2 }, + { 234, 0xbc, 0xbc, 0xbc }, { 235, 0xc6, 0xc6, 0xc6 }, + { 236, 0xd0, 0xd0, 0xd0 }, { 237, 0xda, 0xda, 0xda }, + { 238, 0xe4, 0xe4, 0xe4 }, { 239, 0xee, 0xee, 0xee }, +}; +const struct colour_rgb colour_to_256[] = { + { 0, 0x00, 0x00, 0x00 }, { 1, 0x00, 0x00, 0x5f }, + { 2, 0x00, 0x00, 0x87 }, { 3, 0x00, 0x00, 0xaf }, + { 4, 0x00, 0x00, 0xd7 }, { 5, 0x00, 0x00, 0xff }, + { 6, 0x00, 0x5f, 0x00 }, { 7, 0x00, 0x5f, 0x5f }, + { 8, 0x00, 0x5f, 0x87 }, { 9, 0x00, 0x5f, 0xaf }, + { 10, 0x00, 0x5f, 0xd7 }, { 11, 0x00, 0x5f, 0xff }, + { 12, 0x00, 0x87, 0x00 }, { 13, 0x00, 0x87, 0x5f }, + { 14, 0x00, 0x87, 0x87 }, { 15, 0x00, 0x87, 0xaf }, + { 16, 0x00, 0x87, 0xd7 }, { 17, 0x00, 0x87, 0xff }, + { 18, 0x00, 0xaf, 0x00 }, { 19, 0x00, 0xaf, 0x5f }, + { 20, 0x00, 0xaf, 0x87 }, { 21, 0x00, 0xaf, 0xaf }, + { 22, 0x00, 0xaf, 0xd7 }, { 23, 0x00, 0xaf, 0xff }, + { 24, 0x00, 0xd7, 0x00 }, { 25, 0x00, 0xd7, 0x5f }, + { 26, 0x00, 0xd7, 0x87 }, { 27, 0x00, 0xd7, 0xaf }, + { 28, 0x00, 0xd7, 0xd7 }, { 29, 0x00, 0xd7, 0xff }, + { 30, 0x00, 0xff, 0x00 }, { 31, 0x00, 0xff, 0x5f }, + { 32, 0x00, 0xff, 0x87 }, { 33, 0x00, 0xff, 0xaf }, + { 34, 0x00, 0xff, 0xd7 }, { 35, 0x00, 0xff, 0xff }, + { 216, 0x08, 0x08, 0x08 }, { 217, 0x12, 0x12, 0x12 }, + { 218, 0x1c, 0x1c, 0x1c }, { 219, 0x26, 0x26, 0x26 }, + { 220, 0x30, 0x30, 0x30 }, { 221, 0x3a, 0x3a, 0x3a }, + { 222, 0x44, 0x44, 0x44 }, { 223, 0x4e, 0x4e, 0x4e }, + { 224, 0x58, 0x58, 0x58 }, { 36, 0x5f, 0x00, 0x00 }, + { 37, 0x5f, 0x00, 0x5f }, { 38, 0x5f, 0x00, 0x87 }, + { 39, 0x5f, 0x00, 0xaf }, { 40, 0x5f, 0x00, 0xd7 }, + { 41, 0x5f, 0x00, 0xff }, { 42, 0x5f, 0x5f, 0x00 }, + { 43, 0x5f, 0x5f, 0x5f }, { 44, 0x5f, 0x5f, 0x87 }, + { 45, 0x5f, 0x5f, 0xaf }, { 46, 0x5f, 0x5f, 0xd7 }, + { 47, 0x5f, 0x5f, 0xff }, { 48, 0x5f, 0x87, 0x00 }, + { 49, 0x5f, 0x87, 0x5f }, { 50, 0x5f, 0x87, 0x87 }, + { 51, 0x5f, 0x87, 0xaf }, { 52, 0x5f, 0x87, 0xd7 }, + { 53, 0x5f, 0x87, 0xff }, { 54, 0x5f, 0xaf, 0x00 }, + { 55, 0x5f, 0xaf, 0x5f }, { 56, 0x5f, 0xaf, 0x87 }, + { 57, 0x5f, 0xaf, 0xaf }, { 58, 0x5f, 0xaf, 0xd7 }, + { 59, 0x5f, 0xaf, 0xff }, { 60, 0x5f, 0xd7, 0x00 }, + { 61, 0x5f, 0xd7, 0x5f }, { 62, 0x5f, 0xd7, 0x87 }, + { 63, 0x5f, 0xd7, 0xaf }, { 64, 0x5f, 0xd7, 0xd7 }, + { 65, 0x5f, 0xd7, 0xff }, { 66, 0x5f, 0xff, 0x00 }, + { 67, 0x5f, 0xff, 0x5f }, { 68, 0x5f, 0xff, 0x87 }, + { 69, 0x5f, 0xff, 0xaf }, { 70, 0x5f, 0xff, 0xd7 }, + { 71, 0x5f, 0xff, 0xff }, { 225, 0x62, 0x62, 0x62 }, + { 226, 0x6c, 0x6c, 0x6c }, { 227, 0x76, 0x76, 0x76 }, + { 228, 0x80, 0x80, 0x80 }, { 72, 0x87, 0x00, 0x00 }, + { 73, 0x87, 0x00, 0x5f }, { 74, 0x87, 0x00, 0x87 }, + { 75, 0x87, 0x00, 0xaf }, { 76, 0x87, 0x00, 0xd7 }, + { 77, 0x87, 0x00, 0xff }, { 78, 0x87, 0x5f, 0x00 }, + { 79, 0x87, 0x5f, 0x5f }, { 80, 0x87, 0x5f, 0x87 }, + { 81, 0x87, 0x5f, 0xaf }, { 82, 0x87, 0x5f, 0xd7 }, + { 83, 0x87, 0x5f, 0xff }, { 84, 0x87, 0x87, 0x00 }, + { 85, 0x87, 0x87, 0x5f }, { 86, 0x87, 0x87, 0x87 }, + { 87, 0x87, 0x87, 0xaf }, { 88, 0x87, 0x87, 0xd7 }, + { 89, 0x87, 0x87, 0xff }, { 90, 0x87, 0xaf, 0x00 }, + { 91, 0x87, 0xaf, 0x5f }, { 92, 0x87, 0xaf, 0x87 }, + { 93, 0x87, 0xaf, 0xaf }, { 94, 0x87, 0xaf, 0xd7 }, + { 95, 0x87, 0xaf, 0xff }, { 96, 0x87, 0xd7, 0x00 }, + { 97, 0x87, 0xd7, 0x5f }, { 98, 0x87, 0xd7, 0x87 }, + { 99, 0x87, 0xd7, 0xaf }, { 100, 0x87, 0xd7, 0xd7 }, + { 101, 0x87, 0xd7, 0xff }, { 102, 0x87, 0xff, 0x00 }, + { 103, 0x87, 0xff, 0x5f }, { 104, 0x87, 0xff, 0x87 }, + { 105, 0x87, 0xff, 0xaf }, { 106, 0x87, 0xff, 0xd7 }, + { 107, 0x87, 0xff, 0xff }, { 229, 0x8a, 0x8a, 0x8a }, + { 230, 0x94, 0x94, 0x94 }, { 231, 0x9e, 0x9e, 0x9e }, + { 232, 0xa8, 0xa8, 0xa8 }, { 108, 0xaf, 0x00, 0x00 }, + { 109, 0xaf, 0x00, 0x5f }, { 110, 0xaf, 0x00, 0x87 }, + { 111, 0xaf, 0x00, 0xaf }, { 112, 0xaf, 0x00, 0xd7 }, + { 113, 0xaf, 0x00, 0xff }, { 114, 0xaf, 0x5f, 0x00 }, + { 115, 0xaf, 0x5f, 0x5f }, { 116, 0xaf, 0x5f, 0x87 }, + { 117, 0xaf, 0x5f, 0xaf }, { 118, 0xaf, 0x5f, 0xd7 }, + { 119, 0xaf, 0x5f, 0xff }, { 120, 0xaf, 0x87, 0x00 }, + { 121, 0xaf, 0x87, 0x5f }, { 122, 0xaf, 0x87, 0x87 }, + { 123, 0xaf, 0x87, 0xaf }, { 124, 0xaf, 0x87, 0xd7 }, + { 125, 0xaf, 0x87, 0xff }, { 126, 0xaf, 0xaf, 0x00 }, + { 127, 0xaf, 0xaf, 0x5f }, { 128, 0xaf, 0xaf, 0x87 }, + { 129, 0xaf, 0xaf, 0xaf }, { 130, 0xaf, 0xaf, 0xd7 }, + { 131, 0xaf, 0xaf, 0xff }, { 132, 0xaf, 0xd7, 0x00 }, + { 133, 0xaf, 0xd7, 0x5f }, { 134, 0xaf, 0xd7, 0x87 }, + { 135, 0xaf, 0xd7, 0xaf }, { 136, 0xaf, 0xd7, 0xd7 }, + { 137, 0xaf, 0xd7, 0xff }, { 138, 0xaf, 0xff, 0x00 }, + { 139, 0xaf, 0xff, 0x5f }, { 140, 0xaf, 0xff, 0x87 }, + { 141, 0xaf, 0xff, 0xaf }, { 142, 0xaf, 0xff, 0xd7 }, + { 143, 0xaf, 0xff, 0xff }, { 233, 0xb2, 0xb2, 0xb2 }, + { 234, 0xbc, 0xbc, 0xbc }, { 235, 0xc6, 0xc6, 0xc6 }, + { 236, 0xd0, 0xd0, 0xd0 }, { 144, 0xd7, 0x00, 0x00 }, + { 145, 0xd7, 0x00, 0x5f }, { 146, 0xd7, 0x00, 0x87 }, + { 147, 0xd7, 0x00, 0xaf }, { 148, 0xd7, 0x00, 0xd7 }, + { 149, 0xd7, 0x00, 0xff }, { 150, 0xd7, 0x5f, 0x00 }, + { 151, 0xd7, 0x5f, 0x5f }, { 152, 0xd7, 0x5f, 0x87 }, + { 153, 0xd7, 0x5f, 0xaf }, { 154, 0xd7, 0x5f, 0xd7 }, + { 155, 0xd7, 0x5f, 0xff }, { 156, 0xd7, 0x87, 0x00 }, + { 157, 0xd7, 0x87, 0x5f }, { 158, 0xd7, 0x87, 0x87 }, + { 159, 0xd7, 0x87, 0xaf }, { 160, 0xd7, 0x87, 0xd7 }, + { 161, 0xd7, 0x87, 0xff }, { 162, 0xd7, 0xaf, 0x00 }, + { 163, 0xd7, 0xaf, 0x5f }, { 164, 0xd7, 0xaf, 0x87 }, + { 165, 0xd7, 0xaf, 0xaf }, { 166, 0xd7, 0xaf, 0xd7 }, + { 167, 0xd7, 0xaf, 0xff }, { 168, 0xd7, 0xd7, 0x00 }, + { 169, 0xd7, 0xd7, 0x5f }, { 170, 0xd7, 0xd7, 0x87 }, + { 171, 0xd7, 0xd7, 0xaf }, { 172, 0xd7, 0xd7, 0xd7 }, + { 173, 0xd7, 0xd7, 0xff }, { 174, 0xd7, 0xff, 0x00 }, + { 175, 0xd7, 0xff, 0x5f }, { 176, 0xd7, 0xff, 0x87 }, + { 177, 0xd7, 0xff, 0xaf }, { 178, 0xd7, 0xff, 0xd7 }, + { 179, 0xd7, 0xff, 0xff }, { 237, 0xda, 0xda, 0xda }, + { 238, 0xe4, 0xe4, 0xe4 }, { 239, 0xee, 0xee, 0xee }, + { 180, 0xff, 0x00, 0x00 }, { 181, 0xff, 0x00, 0x5f }, + { 182, 0xff, 0x00, 0x87 }, { 183, 0xff, 0x00, 0xaf }, + { 184, 0xff, 0x00, 0xd7 }, { 185, 0xff, 0x00, 0xff }, + { 186, 0xff, 0x5f, 0x00 }, { 187, 0xff, 0x5f, 0x5f }, + { 188, 0xff, 0x5f, 0x87 }, { 189, 0xff, 0x5f, 0xaf }, + { 190, 0xff, 0x5f, 0xd7 }, { 191, 0xff, 0x5f, 0xff }, + { 192, 0xff, 0x87, 0x00 }, { 193, 0xff, 0x87, 0x5f }, + { 194, 0xff, 0x87, 0x87 }, { 195, 0xff, 0x87, 0xaf }, + { 196, 0xff, 0x87, 0xd7 }, { 197, 0xff, 0x87, 0xff }, + { 198, 0xff, 0xaf, 0x00 }, { 199, 0xff, 0xaf, 0x5f }, + { 200, 0xff, 0xaf, 0x87 }, { 201, 0xff, 0xaf, 0xaf }, + { 202, 0xff, 0xaf, 0xd7 }, { 203, 0xff, 0xaf, 0xff }, + { 204, 0xff, 0xd7, 0x00 }, { 205, 0xff, 0xd7, 0x5f }, + { 206, 0xff, 0xd7, 0x87 }, { 207, 0xff, 0xd7, 0xaf }, + { 208, 0xff, 0xd7, 0xd7 }, { 209, 0xff, 0xd7, 0xff }, + { 210, 0xff, 0xff, 0x00 }, { 211, 0xff, 0xff, 0x5f }, + { 212, 0xff, 0xff, 0x87 }, { 213, 0xff, 0xff, 0xaf }, + { 214, 0xff, 0xff, 0xd7 }, { 215, 0xff, 0xff, 0xff }, +}; -void colour_rgb_generate256(void); -u_int colour_rgb_distance(struct colour_rgb *, struct colour_rgb *); +int colour_rgb_cmp(const void *, const void *); int colour_rgb_find(struct colour_rgb *); -/* Generate 256 colour RGB table. */ -void -colour_rgb_generate256(void) +/* Compare function for bsearch(). */ +int +colour_rgb_cmp(const void *lhs0, const void *rhs0) { - struct colour_rgb *rgb; - u_int i, r, g, b; + const struct colour_rgb *lhs = lhs0, *rhs = rhs0; - /* - * Allocate the table. The first 16 colours are often changed by users - * and terminals so don't include them. - */ - colour_rgb_256 = xcalloc(240, sizeof *colour_rgb_256); + if (lhs->r < rhs->r) + return (-1); + if (lhs->r > rhs->r) + return (1); - /* Add the colours first. */ - r = g = b = 0; - for (i = 240; i > 24; i--) { - rgb = &colour_rgb_256[240 - i]; + if (lhs->g < rhs->g) + return (-1); + if (lhs->g > rhs->g) + return (1); - if (r != 0) - rgb->r = (r * 40) + 55; - if (g != 0) - rgb->g = (g * 40) + 55; - if (b != 0) - rgb->b = (b * 40) + 55; + if (lhs->b < rhs->b) + return (-1); + if (lhs->b > rhs->b) + return (1); - b++; - if (b > 5) { - b = 0; - g++; - } - if (g > 5) { - g = 0; - r++; - } - } - - /* Then add the greys. */ - for (i = 24; i > 0; i--) { - rgb = &colour_rgb_256[240 - i]; - - rgb->r = 8 + (24 - i) * 10; - rgb->g = 8 + (24 - i) * 10; - rgb->b = 8 + (24 - i) * 10; - } -} - -/* Get colour RGB distance. */ -u_int -colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2) -{ - int r, g, b; - - r = rgb1->r - rgb2->r; - g = rgb1->g - rgb2->g; - b = rgb1->b - rgb2->b; - return (r * r + g * g + b * b); + return (0); } /* Work out the nearest colour from the 256 colour set. */ int colour_rgb_find(struct colour_rgb *rgb) { - u_int distance, lowest, colour, i; + struct colour_rgb *found; + u_int distance, lowest, colour, i; + int r, g, b; - if (colour_rgb_256 == NULL) - colour_rgb_generate256(); + found = bsearch(rgb, colour_to_256, nitems(colour_to_256), + sizeof colour_to_256[0], colour_rgb_cmp); + if (found != NULL) + return (16 + found->i); colour = 16; lowest = UINT_MAX; for (i = 0; i < 240; i++) { - distance = colour_rgb_distance(&colour_rgb_256[i], rgb); + r = colour_from_256[i].r - rgb->r; + g = colour_from_256[i].g - rgb->g; + b = colour_from_256[i].b - rgb->b; + + distance = r * r + g * g + b * b; if (distance < lowest) { lowest = distance; colour = 16 + i; @@ -217,47 +432,39 @@ colour_fromstring(const char *s) return (n | 0x100); } - if (strcasecmp(s, "black") == 0 || (s[0] == '0' && s[1] == '\0')) + if (strcasecmp(s, "black") == 0 || strcmp(s, "0") == 0) return (0); - if (strcasecmp(s, "red") == 0 || (s[0] == '1' && s[1] == '\0')) + if (strcasecmp(s, "red") == 0 || strcmp(s, "1") == 0) return (1); - if (strcasecmp(s, "green") == 0 || (s[0] == '2' && s[1] == '\0')) + if (strcasecmp(s, "green") == 0 || strcmp(s, "2") == 0) return (2); - if (strcasecmp(s, "yellow") == 0 || (s[0] == '3' && s[1] == '\0')) + if (strcasecmp(s, "yellow") == 0 || strcmp(s, "3") == 0) return (3); - if (strcasecmp(s, "blue") == 0 || (s[0] == '4' && s[1] == '\0')) + if (strcasecmp(s, "blue") == 0 || strcmp(s, "4") == 0) return (4); - if (strcasecmp(s, "magenta") == 0 || (s[0] == '5' && s[1] == '\0')) + if (strcasecmp(s, "magenta") == 0 || strcmp(s, "5") == 0) return (5); - if (strcasecmp(s, "cyan") == 0 || (s[0] == '6' && s[1] == '\0')) + if (strcasecmp(s, "cyan") == 0 || strcmp(s, "6") == 0) return (6); - if (strcasecmp(s, "white") == 0 || (s[0] == '7' && s[1] == '\0')) + if (strcasecmp(s, "white") == 0 || strcmp(s, "7") == 0) return (7); - if (strcasecmp(s, "default") == 0 || (s[0] == '8' && s[1] == '\0')) + if (strcasecmp(s, "default") == 0 || strcmp(s, "8") == 0) return (8); - if (strcasecmp(s, "brightblack") == 0 || - (s[0] == '9' && s[1] == '0' && s[2] == '\0')) + if (strcasecmp(s, "brightblack") == 0 || strcmp(s, "90") == 0) return (90); - if (strcasecmp(s, "brightred") == 0 || - (s[0] == '9' && s[1] == '1' && s[2] == '\0')) + if (strcasecmp(s, "brightred") == 0 || strcmp(s, "91") == 0) return (91); - if (strcasecmp(s, "brightgreen") == 0 || - (s[0] == '9' && s[1] == '2' && s[2] == '\0')) + if (strcasecmp(s, "brightgreen") == 0 || strcmp(s, "92") == 0) return (92); - if (strcasecmp(s, "brightyellow") == 0 || - (s[0] == '9' && s[1] == '3' && s[2] == '\0')) + if (strcasecmp(s, "brightyellow") == 0 || strcmp(s, "93") == 0) return (93); - if (strcasecmp(s, "brightblue") == 0 || - (s[0] == '9' && s[1] == '4' && s[2] == '\0')) + if (strcasecmp(s, "brightblue") == 0 || strcmp(s, "94") == 0) return (94); - if (strcasecmp(s, "brightmagenta") == 0 || - (s[0] == '9' && s[1] == '5' && s[2] == '\0')) + if (strcasecmp(s, "brightmagenta") == 0 || strcmp(s, "95") == 0) return (95); - if (strcasecmp(s, "brightcyan") == 0 || - (s[0] == '9' && s[1] == '6' && s[2] == '\0')) + if (strcasecmp(s, "brightcyan") == 0 || strcmp(s, "96") == 0) return (96); - if (strcasecmp(s, "brightwhite") == 0 || - (s[0] == '9' && s[1] == '7' && s[2] == '\0')) + if (strcasecmp(s, "brightwhite") == 0 || strcmp(s, "97") == 0) return (97); return (-1); } From 55b96a5bd5786f162b258c58627deb8e829cabd7 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 5 Jun 2015 22:33:39 +0000 Subject: [PATCH 10/12] Handle the RGB colour escape sequence (\033[38;2;;;m and 48;2) like xterm(1) does, by mapping to the nearest in the 256 colour palette. --- colour.c | 34 ++++++++++----------- input.c | 91 ++++++++++++++++++++++++++++++++++++++++++-------------- tmux.h | 1 + 3 files changed, 85 insertions(+), 41 deletions(-) diff --git a/colour.c b/colour.c index 5929e982..ac4b72fa 100644 --- a/colour.c +++ b/colour.c @@ -281,12 +281,11 @@ const struct colour_rgb colour_to_256[] = { { 214, 0xff, 0xff, 0xd7 }, { 215, 0xff, 0xff, 0xff }, }; -int colour_rgb_cmp(const void *, const void *); -int colour_rgb_find(struct colour_rgb *); +int colour_cmp_rgb(const void *, const void *); /* Compare function for bsearch(). */ int -colour_rgb_cmp(const void *lhs0, const void *rhs0) +colour_cmp_rgb(const void *lhs0, const void *rhs0) { const struct colour_rgb *lhs = lhs0, *rhs = rhs0; @@ -310,23 +309,22 @@ colour_rgb_cmp(const void *lhs0, const void *rhs0) /* Work out the nearest colour from the 256 colour set. */ int -colour_rgb_find(struct colour_rgb *rgb) +colour_find_rgb(u_char r, u_char g, u_char b) { - struct colour_rgb *found; - u_int distance, lowest, colour, i; - int r, g, b; + struct colour_rgb rgb = { .r = r, .g = g, .b = b }, *found; + u_int distance, lowest, colour, i; - found = bsearch(rgb, colour_to_256, nitems(colour_to_256), - sizeof colour_to_256[0], colour_rgb_cmp); + found = bsearch(&rgb, colour_to_256, nitems(colour_to_256), + sizeof colour_to_256[0], colour_cmp_rgb); if (found != NULL) return (16 + found->i); colour = 16; lowest = UINT_MAX; for (i = 0; i < 240; i++) { - r = colour_from_256[i].r - rgb->r; - g = colour_from_256[i].g - rgb->g; - b = colour_from_256[i].b - rgb->b; + r = colour_from_256[i].r - rgb.r; + g = colour_from_256[i].g - rgb.g; + b = colour_from_256[i].b - rgb.b; distance = r * r + g * g + b * b; if (distance < lowest) { @@ -409,20 +407,20 @@ colour_tostring(int c) int colour_fromstring(const char *s) { - const char *errstr; - const char *cp; - struct colour_rgb rgb; - int n; + const char *errstr; + const char *cp; + int n; + u_char r, g, b; if (*s == '#' && strlen(s) == 7) { for (cp = s + 1; isxdigit((u_char) *cp); cp++) ; if (*cp != '\0') return (-1); - n = sscanf(s + 1, "%2hhx%2hhx%2hhx", &rgb.r, &rgb.g, &rgb.b); + n = sscanf(s + 1, "%2hhx%2hhx%2hhx", &r, &g, &b); if (n != 3) return (-1); - return (colour_rgb_find(&rgb) | 0x100); + return (colour_find_rgb(r, g, b) | 0x100); } if (strncasecmp(s, "colour", (sizeof "colour") - 1) == 0) { diff --git a/input.c b/input.c index 41c0bc85..7a371c62 100644 --- a/input.c +++ b/input.c @@ -126,6 +126,8 @@ void input_csi_dispatch_rm_private(struct input_ctx *); void input_csi_dispatch_sm(struct input_ctx *); void input_csi_dispatch_sm_private(struct input_ctx *); void input_csi_dispatch_winops(struct input_ctx *); +void input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *); +void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *); void input_csi_dispatch_sgr(struct input_ctx *); int input_dcs_dispatch(struct input_ctx *); int input_utf8_open(struct input_ctx *); @@ -1609,13 +1611,71 @@ input_csi_dispatch_winops(struct input_ctx *ictx) } } +/* Handle CSI SGR for 256 colours. */ +void +input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i) +{ + struct grid_cell *gc = &ictx->cell.cell; + int c; + + (*i)++; + c = input_get(ictx, *i, 0, -1); + if (c == -1) { + if (fgbg == 38) { + gc->flags &= ~GRID_FLAG_FG256; + gc->fg = 8; + } else if (fgbg == 48) { + gc->flags &= ~GRID_FLAG_BG256; + gc->bg = 8; + } + } else { + if (fgbg == 38) { + gc->flags |= GRID_FLAG_FG256; + gc->fg = c; + } else if (fgbg == 48) { + gc->flags |= GRID_FLAG_BG256; + gc->bg = c; + } + } +} + +/* Handle CSI SGR for RGB colours. */ +void +input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i) +{ + struct grid_cell *gc = &ictx->cell.cell; + int c, r, g, b; + + (*i)++; + r = input_get(ictx, *i, 0, -1); + if (r == -1 || r > 255) + return; + (*i)++; + g = input_get(ictx, *i, 0, -1); + if (g == -1 || g > 255) + return; + (*i)++; + b = input_get(ictx, *i, 0, -1); + if (b == -1 || b > 255) + return; + + c = colour_find_rgb(r, g, b); + if (fgbg == 38) { + gc->flags |= GRID_FLAG_FG256; + gc->fg = c; + } else if (fgbg == 48) { + gc->flags |= GRID_FLAG_BG256; + gc->bg = c; + } +} + /* Handle CSI SGR. */ void input_csi_dispatch_sgr(struct input_ctx *ictx) { struct grid_cell *gc = &ictx->cell.cell; u_int i; - int n, m; + int n; if (ictx->param_list_len == 0) { memcpy(gc, &grid_default_cell, sizeof *gc); @@ -1627,28 +1687,13 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) if (n == 38 || n == 48) { i++; - if (input_get(ictx, i, 0, -1) != 5) - continue; - - i++; - m = input_get(ictx, i, 0, -1); - if (m == -1) { - if (n == 38) { - gc->flags &= ~GRID_FLAG_FG256; - gc->fg = 8; - } else if (n == 48) { - gc->flags &= ~GRID_FLAG_BG256; - gc->bg = 8; - } - - } else { - if (n == 38) { - gc->flags |= GRID_FLAG_FG256; - gc->fg = m; - } else if (n == 48) { - gc->flags |= GRID_FLAG_BG256; - gc->bg = m; - } + switch (input_get(ictx, i, 0, -1)) { + case 2: + input_csi_dispatch_sgr_rgb(ictx, n, &i); + break; + case 5: + input_csi_dispatch_sgr_256(ictx, n, &i); + break; } continue; } diff --git a/tmux.h b/tmux.h index 699ee81e..4ddf5c4a 100644 --- a/tmux.h +++ b/tmux.h @@ -1953,6 +1953,7 @@ char *xterm_keys_lookup(int); int xterm_keys_find(const char *, size_t, size_t *, int *); /* colour.c */ +int colour_find_rgb(u_char, u_char, u_char); void colour_set_fg(struct grid_cell *, int); void colour_set_bg(struct grid_cell *, int); const char *colour_tostring(int); From ed6c036ee3192029e9d0a60e8f9bb2a4ccfb99bf Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 5 Jun 2015 22:50:27 +0000 Subject: [PATCH 11/12] Use ints for the calculations rather than u_char, they could end up signed. --- colour.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/colour.c b/colour.c index ac4b72fa..a56ddce9 100644 --- a/colour.c +++ b/colour.c @@ -313,6 +313,7 @@ colour_find_rgb(u_char r, u_char g, u_char b) { struct colour_rgb rgb = { .r = r, .g = g, .b = b }, *found; u_int distance, lowest, colour, i; + int dr, dg, db; found = bsearch(&rgb, colour_to_256, nitems(colour_to_256), sizeof colour_to_256[0], colour_cmp_rgb); @@ -322,11 +323,11 @@ colour_find_rgb(u_char r, u_char g, u_char b) colour = 16; lowest = UINT_MAX; for (i = 0; i < 240; i++) { - r = colour_from_256[i].r - rgb.r; - g = colour_from_256[i].g - rgb.g; - b = colour_from_256[i].b - rgb.b; + dr = (int)colour_from_256[i].r - r; + dg = (int)colour_from_256[i].g - g; + db = (int)colour_from_256[i].b - b; - distance = r * r + g * g + b * b; + distance = dr * dr + dg * dg + db * db; if (distance < lowest) { lowest = distance; colour = 16 + i; From c4e811e51936edab66803a7b9e099ac135e6e19b Mon Sep 17 00:00:00 2001 From: nicm Date: Sun, 7 Jun 2015 21:39:39 +0000 Subject: [PATCH 12/12] Add -E flag when attaching or switching client to bypass update-environment, from Steven Lu. --- cmd-attach-session.c | 50 ++++++++++++++++++++++++-------------------- cmd-new-session.c | 13 +++++++----- cmd-switch-client.c | 6 +++--- tmux.1 | 25 +++++++++++++++++++--- tmux.h | 2 +- 5 files changed, 61 insertions(+), 35 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index f889019c..b2a2f8c5 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -34,18 +34,18 @@ enum cmd_retval cmd_attach_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_attach_session_entry = { "attach-session", "attach", - "c:drt:", 0, 0, - "[-dr] [-c working-directory] " CMD_TARGET_SESSION_USAGE, + "c:dErt:", 0, 0, + "[-dEr] [-c working-directory] " CMD_TARGET_SESSION_USAGE, CMD_STARTSERVER, cmd_attach_session_exec }; enum cmd_retval cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, - const char *cflag) + const char *cflag, int Eflag) { struct session *s; - struct client *c; + struct client *c = cmdq->client, *c_loop; struct winlink *wl = NULL; struct window *w = NULL; struct window_pane *wp = NULL; @@ -79,9 +79,9 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, wl = winlink_find_by_window(&s->windows, w); } - if (cmdq->client == NULL) + if (c == NULL) return (CMD_RETURN_NORMAL); - if (server_client_check_nested(cmdq->client)) { + if (server_client_check_nested(c)) { cmdq_error(cmdq, "sessions should be nested with care, " "unset $TMUX to force"); return (CMD_RETURN_ERROR); @@ -93,18 +93,18 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, session_set_current(s, wl); } - if (cmdq->client->session != NULL) { + if (c->session != NULL) { if (dflag) { /* * Can't use server_write_session in case attaching to * the same session as currently attached to. */ - TAILQ_FOREACH(c, &clients, entry) { - if (c->session != s || c == cmdq->client) + TAILQ_FOREACH(c_loop, &clients, entry) { + if (c_loop->session != s || c == c) continue; server_write_client(c, MSG_DETACH, - c->session->name, - strlen(c->session->name) + 1); + c_loop->session->name, + strlen(c_loop->session->name) + 1); } } @@ -126,13 +126,13 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, s->cwd = fd; } - cmdq->client->session = s; - notify_attached_session_changed(cmdq->client); + c->session = s; + notify_attached_session_changed(c); session_update_activity(s); - server_redraw_client(cmdq->client); + server_redraw_client(c); s->curw->flags &= ~WINLINK_ALERTFLAGS; } else { - if (server_client_open(cmdq->client, &cause) != 0) { + if (server_client_open(c, &cause) != 0) { cmdq_error(cmdq, "open terminal failed: %s", cause); free(cause); return (CMD_RETURN_ERROR); @@ -157,23 +157,26 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, } if (rflag) - cmdq->client->flags |= CLIENT_READONLY; + c->flags |= CLIENT_READONLY; if (dflag) { server_write_session(s, MSG_DETACH, s->name, strlen(s->name) + 1); } - update = options_get_string(&s->options, "update-environment"); - environ_update(update, &cmdq->client->environ, &s->environ); + if (!Eflag) { + update = options_get_string(&s->options, + "update-environment"); + environ_update(update, &c->environ, &s->environ); + } - cmdq->client->session = s; - notify_attached_session_changed(cmdq->client); + c->session = s; + notify_attached_session_changed(c); session_update_activity(s); - server_redraw_client(cmdq->client); + server_redraw_client(c); s->curw->flags &= ~WINLINK_ALERTFLAGS; - server_write_ready(cmdq->client); + server_write_ready(c); cmdq->client_exit = 0; } recalculate_sizes(); @@ -188,5 +191,6 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_q *cmdq) struct args *args = self->args; return (cmd_attach_session(cmdq, args_get(args, 't'), - args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c'))); + args_has(args, 'd'), args_has(args, 'r'), args_get(args, 'c'), + args_has(args, 'E'))); } diff --git a/cmd-new-session.c b/cmd-new-session.c index 0fb849e2..1533e5f0 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -37,8 +37,8 @@ enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_new_session_entry = { "new-session", "new", - "Ac:dDF:n:Ps:t:x:y:", 0, -1, - "[-AdDP] [-c start-directory] [-F format] [-n window-name] " + "Ac:dDEF:n:Ps:t:x:y:", 0, -1, + "[-AdDEP] [-c start-directory] [-F format] [-n window-name] " "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] " "[-y height] [command]", CMD_STARTSERVER, @@ -91,7 +91,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (session_find(newname) != NULL) { if (args_has(args, 'A')) { return (cmd_attach_session(cmdq, newname, - args_has(args, 'D'), 0, NULL)); + args_has(args, 'D'), 0, NULL, + args_has(args, 'E'))); } cmdq_error(cmdq, "duplicate session: %s", newname); return (CMD_RETURN_ERROR); @@ -230,9 +231,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) /* Construct the environment. */ environ_init(&env); - update = options_get_string(&global_s_options, "update-environment"); - if (c != NULL) + if (c != NULL && !args_has(args, 'E')) { + update = options_get_string(&global_s_options, + "update-environment"); environ_update(update, &c->environ, &env); + } /* Create the new session. */ idx = -1 - options_get_number(&global_s_options, "base-index"); diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 369fc917..23751d73 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -31,8 +31,8 @@ enum cmd_retval cmd_switch_client_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_switch_client_entry = { "switch-client", "switchc", - "lc:npt:rT:", 0, 0, - "[-lnpr] [-c target-client] [-t target-session] [-T key-table]", + "lc:Enpt:rT:", 0, 0, + "[-Elnpr] [-c target-client] [-t target-session] [-T key-table]", CMD_READONLY, cmd_switch_client_exec }; @@ -119,7 +119,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq) } } - if (c != NULL && s != c->session) { + if (c != NULL && s != c->session && !args_has(args, 'E')) { update = options_get_string(&s->options, "update-environment"); environ_update(update, &c->environ, &s->environ); } diff --git a/tmux.1 b/tmux.1 index 7ad33530..16e979ad 100644 --- a/tmux.1 +++ b/tmux.1 @@ -670,7 +670,7 @@ section. The following commands are available to manage clients and sessions: .Bl -tag -width Ds .It Xo Ic attach-session -.Op Fl dr +.Op Fl dEr .Op Fl c Ar working-directory .Op Fl t Ar target-session .Xc @@ -709,6 +709,12 @@ session. .Fl c will set the session working directory (used for new windows) to .Ar working-directory . +.Pp +If +.Fl E +is used, +.Ic update-environment +option will not be applied. .It Xo Ic detach-client .Op Fl P .Op Fl a @@ -783,7 +789,7 @@ command. Lock all clients attached to .Ar target-session . .It Xo Ic new-session -.Op Fl AdDP +.Op Fl AdDEP .Op Fl c Ar start-directory .Op Fl F Ar format .Op Fl n Ar window-name @@ -858,6 +864,13 @@ By default, it uses the format .Ql #{session_name}: but a different format may be specified with .Fl F . +.Pp +If +.Fl E +is used, +.Ic update-environment +option will not be applied. +.Ic update-environment . .It Xo Ic refresh-client .Op Fl S .Op Fl t Ar target-client @@ -912,7 +925,7 @@ Suspend a client by sending .Dv SIGTSTP (tty stop). .It Xo Ic switch-client -.Op Fl lnpr +.Op Fl Elnpr .Op Fl c Ar target-client .Op Fl t Ar target-session .Op Fl T Ar key-table @@ -934,6 +947,12 @@ toggles whether a client is read-only (see the .Ic attach-session command). .Pp +If +.Fl E +is used, +.Ic update-environment +option will not be applied. +.Pp .Fl T sets the client's key table; the next key from the client will be interpreted from .Ar key-table . diff --git a/tmux.h b/tmux.h index 4ddf5c4a..265fdc40 100644 --- a/tmux.h +++ b/tmux.h @@ -1801,7 +1801,7 @@ extern const struct cmd_entry cmd_wait_for_entry; /* cmd-attach-session.c */ enum cmd_retval cmd_attach_session(struct cmd_q *, const char *, int, int, - const char *); + const char *, int); /* cmd-list.c */ struct cmd_list *cmd_list_parse(int, char **, const char *, u_int, char **);