From 30275bc61081023b4e0a56452e90fac23c6f6b60 Mon Sep 17 00:00:00 2001 From: okan Date: Sun, 17 Nov 2013 20:19:36 +0000 Subject: [PATCH 01/26] Include unistd.h as it is the standard location for getopt(). OK millert@ --- arguments.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arguments.c b/arguments.c index ca828f00..e699834c 100644 --- a/arguments.c +++ b/arguments.c @@ -20,6 +20,7 @@ #include #include +#include #include "tmux.h" From 72a4602b880357776d3a2ea7657cf88f3393c288 Mon Sep 17 00:00:00 2001 From: deraadt Date: Wed, 20 Nov 2013 17:01:23 +0000 Subject: [PATCH 02/26] missing unsigned char casts areound tolower() ok nicm --- window-copy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/window-copy.c b/window-copy.c index 0c122cda..dd4f23fa 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1030,7 +1030,7 @@ window_copy_search_up(struct window_pane *wp, const char *searchstr) cis = 1; for (ptr = searchstr; *ptr != '\0'; ptr++) { - if (*ptr != tolower(*ptr)) { + if (*ptr != tolower((u_char)*ptr)) { cis = 0; break; } @@ -1097,7 +1097,7 @@ window_copy_search_down(struct window_pane *wp, const char *searchstr) cis = 1; for (ptr = searchstr; *ptr != '\0'; ptr++) { - if (*ptr != tolower(*ptr)) { + if (*ptr != tolower((u_char)*ptr)) { cis = 0; break; } From 7aeb4473add76e11dd595919f81ff5d9cad28718 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 22 Nov 2013 20:58:36 +0000 Subject: [PATCH 03/26] Handle empty current directory more gracefully. --- cmd-new-session.c | 17 ++++++++++------- cmd-new-window.c | 17 ++++++++++------- cmd-split-window.c | 17 ++++++++++------- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index 49ece8b4..bf843cad 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -107,13 +107,16 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) cp = format_expand(ft, args_get(args, 'c')); format_free(ft); - fd = open(cp, O_RDONLY|O_DIRECTORY); - free(cp); - if (fd == -1) { - cmdq_error(cmdq, "bad working directory: %s", - strerror(errno)); - return (CMD_RETURN_ERROR); - } + if (cp != NULL && *cp != '\0') { + fd = open(cp, O_RDONLY|O_DIRECTORY); + free(cp); + if (fd == -1) { + cmdq_error(cmdq, "bad working directory: %s", + strerror(errno)); + return (CMD_RETURN_ERROR); + } + } else if (cp != NULL) + free(cp); cwd = fd; } else if (c != NULL && c->session == NULL) cwd = c->cwd; diff --git a/cmd-new-window.c b/cmd-new-window.c index e2a01190..354d0ae5 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -117,13 +117,16 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) cp = format_expand(ft, args_get(args, 'c')); format_free(ft); - fd = open(cp, O_RDONLY|O_DIRECTORY); - free(cp); - if (fd == -1) { - cmdq_error(cmdq, "bad working directory: %s", - strerror(errno)); - return (CMD_RETURN_ERROR); - } + if (cp != NULL && *cp != '\0') { + fd = open(cp, O_RDONLY|O_DIRECTORY); + free(cp); + if (fd == -1) { + cmdq_error(cmdq, "bad working directory: %s", + strerror(errno)); + return (CMD_RETURN_ERROR); + } + } else if (cp != NULL) + free(cp); cwd = fd; } else if (cmdq->client != NULL && cmdq->client->session == NULL) cwd = cmdq->client->cwd; diff --git a/cmd-split-window.c b/cmd-split-window.c index 92e6121f..a431e000 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -95,13 +95,16 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) cp = format_expand(ft, args_get(args, 'c')); format_free(ft); - fd = open(cp, O_RDONLY|O_DIRECTORY); - free(cp); - if (fd == -1) { - cmdq_error(cmdq, "bad working directory: %s", - strerror(errno)); - return (CMD_RETURN_ERROR); - } + if (cp != NULL && *cp != '\0') { + fd = open(cp, O_RDONLY|O_DIRECTORY); + free(cp); + if (fd == -1) { + cmdq_error(cmdq, "bad working directory: %s", + strerror(errno)); + return (CMD_RETURN_ERROR); + } + } else if (cp != NULL) + free(cp); cwd = fd; } else if (cmdq->client != NULL && cmdq->client->session == NULL) cwd = cmdq->client->cwd; From 40982a01fb39b7be749bc807a06ba352dd6c2e5e Mon Sep 17 00:00:00 2001 From: nicm Date: Sat, 23 Nov 2013 09:18:29 +0000 Subject: [PATCH 04/26] With -k, kill window after using it to work out -c path. Reported by jmacristovao at gmail dot com. --- cmd-new-window.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/cmd-new-window.c b/cmd-new-window.c index 354d0ae5..e205e6bc 100644 --- a/cmd-new-window.c +++ b/cmd-new-window.c @@ -82,26 +82,6 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) } detached = args_has(args, 'd'); - wl = NULL; - if (idx != -1) - wl = winlink_find_by_index(&s->windows, idx); - if (wl != NULL && args_has(args, 'k')) { - /* - * Can't use session_detach as it will destroy session if this - * makes it empty. - */ - notify_window_unlinked(s, wl->window); - wl->flags &= ~WINLINK_ALERTFLAGS; - winlink_stack_remove(&s->lastw, wl); - winlink_remove(&s->windows, wl); - - /* Force select/redraw if current. */ - if (wl == s->curw) { - detached = 0; - s->curw = NULL; - } - } - if (args->argc == 0) cmd = options_get_string(&s->options, "default-command"); else @@ -133,6 +113,26 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) else cwd = s->cwd; + wl = NULL; + if (idx != -1) + wl = winlink_find_by_index(&s->windows, idx); + if (wl != NULL && args_has(args, 'k')) { + /* + * Can't use session_detach as it will destroy session if this + * makes it empty. + */ + notify_window_unlinked(s, wl->window); + wl->flags &= ~WINLINK_ALERTFLAGS; + winlink_stack_remove(&s->lastw, wl); + winlink_remove(&s->windows, wl); + + /* Force select/redraw if current. */ + if (wl == s->curw) { + detached = 0; + s->curw = NULL; + } + } + if (idx == -1) idx = -1 - options_get_number(&s->options, "base-index"); wl = session_new(s, args_get(args, 'n'), cmd, cwd, idx, &cause); From 1286c56188502e217c49f712faba66ee4178f964 Mon Sep 17 00:00:00 2001 From: nicm Date: Sun, 24 Nov 2013 11:29:09 +0000 Subject: [PATCH 05/26] Replace ## by # in format. --- format.c | 7 +++++++ tmux.1 | 3 +++ 2 files changed, 10 insertions(+) diff --git a/format.c b/format.c index bfc40906..bcb897d6 100644 --- a/format.c +++ b/format.c @@ -321,6 +321,13 @@ format_expand(struct format_tree *ft, const char *fmt) break; fmt += n + 1; continue; + case '#': + while (len - off < 2) { + buf = xrealloc(buf, 2, len); + len *= 2; + } + buf[off++] = '#'; + continue; default: s = NULL; if (ch >= 'A' && ch <= 'Z') diff --git a/tmux.1 b/tmux.1 index e815fc4e..a2404b4f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3011,6 +3011,9 @@ for example .Ql #{session_name} . Some variables also have an shorter alias such as .Ql #S . +.Ql ## +is replaced by a single +.Ql # . Conditionals are also accepted by prefixing with .Ql \&? and separating two alternatives with a comma; From d459314517151dd5a7ffcb3eb93d44f481ca8626 Mon Sep 17 00:00:00 2001 From: nicm Date: Sun, 24 Nov 2013 19:38:32 +0000 Subject: [PATCH 06/26] Add comments to ACS table matching terminfo(5). --- tty-acs.c | 64 +++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/tty-acs.c b/tty-acs.c index 297c51ac..13dbbc72 100644 --- a/tty-acs.c +++ b/tty-acs.c @@ -30,38 +30,38 @@ struct tty_acs_entry { const char *string; }; const struct tty_acs_entry tty_acs_table[] = { - { '+', "\342\206\222" }, - { ',', "\342\206\220" }, - { '-', "\342\206\221" }, - { '.', "\342\206\223" }, - { '0', "\342\226\256" }, - { '`', "\342\227\206" }, - { 'a', "\342\226\222" }, - { 'f', "\302\260" }, - { 'g', "\302\261" }, - { 'h', "\342\226\222" }, - { 'i', "\342\230\203" }, - { 'j', "\342\224\230" }, - { 'k', "\342\224\220" }, - { 'l', "\342\224\214" }, - { 'm', "\342\224\224" }, - { 'n', "\342\224\274" }, - { 'o', "\342\216\272" }, - { 'p', "\342\216\273" }, - { 'q', "\342\224\200" }, - { 'r', "\342\216\274" }, - { 's', "\342\216\275" }, - { 't', "\342\224\234" }, - { 'u', "\342\224\244" }, - { 'v', "\342\224\264" }, - { 'w', "\342\224\254" }, - { 'x', "\342\224\202" }, - { 'y', "\342\211\244" }, - { 'z', "\342\211\245" }, - { '{', "\317\200" }, - { '|', "\342\211\240" }, - { '}', "\302\243" }, - { '~', "\302\267" } + { '+', "\342\206\222" }, /* arrow pointing right */ + { ',', "\342\206\220" }, /* arrow pointing left */ + { '-', "\342\206\221" }, /* arrow pointing up */ + { '.', "\342\206\223" }, /* arrow pointing down */ + { '0', "\342\226\256" }, /* solid square block */ + { '`', "\342\227\206" }, /* diamond */ + { 'a', "\342\226\222" }, /* checker board (stipple) */ + { 'f', "\302\260" }, /* degree symbol */ + { 'g', "\302\261" }, /* plus/minus */ + { 'h', "\342\226\222" }, /* board of squares */ + { 'i', "\342\230\203" }, /* lantern symbol */ + { 'j', "\342\224\230" }, /* lower right corner */ + { 'k', "\342\224\220" }, /* upper right corner */ + { 'l', "\342\224\214" }, /* upper left corner */ + { 'm', "\342\224\224" }, /* lower left corner */ + { 'n', "\342\224\274" }, /* large plus or crossover */ + { 'o', "\342\216\272" }, /* scan line 1 */ + { 'p', "\342\216\273" }, /* scan line 3 */ + { 'q', "\342\224\200" }, /* horizontal line */ + { 'r', "\342\216\274" }, /* scan line 7 */ + { 's', "\342\216\275" }, /* scan line 9 */ + { 't', "\342\224\234" }, /* tee pointing right */ + { 'u', "\342\224\244" }, /* tee pointing left */ + { 'v', "\342\224\264" }, /* tee pointing up */ + { 'w', "\342\224\254" }, /* tee pointing down */ + { 'x', "\342\224\202" }, /* vertical line */ + { 'y', "\342\211\244" }, /* less-than-or-equal-to */ + { 'z', "\342\211\245" }, /* greater-than-or-equal-to */ + { '{', "\317\200" }, /* greek pi */ + { '|', "\342\211\240" }, /* not-equal */ + { '}', "\302\243" }, /* UK pound sign */ + { '~', "\302\267" } /* bullet */ }; int From 1751da76d5fed929636633905be5f5cfa204844b Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 9 Jan 2014 13:46:12 +0000 Subject: [PATCH 07/26] Remove unnecessary calls to va_start/va_end, from Tiago Cunha. --- cmd-queue.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cmd-queue.c b/cmd-queue.c index bb3a09ec..caa80afe 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -69,9 +69,7 @@ cmdq_print(struct cmd_q *cmdq, const char *fmt, ...) if (c == NULL) /* nothing */; else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) { - va_start(ap, fmt); evbuffer_add_vprintf(c->stdout_data, fmt, ap); - va_end(ap); evbuffer_add(c->stdout_data, "\n", 1); server_push_stdout(c); @@ -104,9 +102,7 @@ cmdq_info(struct cmd_q *cmdq, const char *fmt, ...) if (c == NULL) /* nothing */; else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) { - va_start(ap, fmt); evbuffer_add_vprintf(c->stdout_data, fmt, ap); - va_end(ap); evbuffer_add(c->stdout_data, "\n", 1); server_push_stdout(c); From 66829ee12e45656fccfe8879b7ac2f983d138b42 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 9 Jan 2014 13:51:57 +0000 Subject: [PATCH 08/26] Simplify args_set, from Tiago Cunha. --- arguments.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/arguments.c b/arguments.c index e699834c..4a3f4579 100644 --- a/arguments.c +++ b/arguments.c @@ -205,19 +205,15 @@ args_set(struct args *args, u_char ch, const char *value) /* Replace existing argument. */ if ((entry = args_find(args, ch)) != NULL) { free(entry->value); - if (value != NULL) - entry->value = xstrdup(value); - else - entry->value = NULL; - return; + entry->value = NULL; + } else { + entry = xcalloc(1, sizeof *entry); + entry->flag = ch; + RB_INSERT(args_tree, &args->tree, entry); } - entry = xcalloc(1, sizeof *entry); - entry->flag = ch; if (value != NULL) entry->value = xstrdup(value); - - RB_INSERT(args_tree, &args->tree, entry); } /* Get argument value. Will be NULL if it isn't present. */ From 994cb872cfb5ef49a08a714d093d92bfee79b0e8 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 9 Jan 2014 13:58:06 +0000 Subject: [PATCH 09/26] Style and comment fixes from Tiago Cunha. --- grid.c | 2 +- options.c | 2 +- window-choose.c | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/grid.c b/grid.c index d06e7154..d9b3c716 100644 --- a/grid.c +++ b/grid.c @@ -644,7 +644,7 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, if (trim) { while (off > 0 && buf[off - 1] == ' ') off--; - } + } buf[off] = '\0'; return (buf); diff --git a/options.c b/options.c index ec036741..51a6608e 100644 --- a/options.c +++ b/options.c @@ -26,7 +26,7 @@ /* * Option handling; each option has a name, type and value and is stored in - * a splay tree. + * a red-black tree. */ RB_GENERATE(options_tree, options_entry, entry, options_cmp); diff --git a/window-choose.c b/window-choose.c index 70c20085..77add5e4 100644 --- a/window-choose.c +++ b/window-choose.c @@ -345,8 +345,7 @@ window_choose_collapse(struct window_pane *wp, struct session *s) * assign the actual result we want to render and copy the new one over * the top of it. */ - for (i = 0; i < ARRAY_LENGTH(&data->list); i++) - { + for (i = 0; i < ARRAY_LENGTH(&data->list); i++) { item = &ARRAY_ITEM(&data->list, i); wcd = item->wcd; From adc1f21eaee899b8ecfdb6ef3676d9a25019e4fa Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 9 Jan 2014 14:05:55 +0000 Subject: [PATCH 10/26] Three small changes from Tiago Cunha: - Check for truncation when copying path. - Don't need to use a temporary buffer in screen_set_title. - Include strerror in output when connecting to server fails. --- client.c | 3 ++- screen.c | 6 +----- tmux.c | 6 +++++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/client.c b/client.c index 82ef9cf0..1458963c 100644 --- a/client.c +++ b/client.c @@ -232,7 +232,8 @@ client_main(int argc, char **argv, int flags) /* Initialise the client socket and start the server. */ fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER); if (fd == -1) { - fprintf(stderr, "failed to connect to server\n"); + fprintf(stderr, "failed to connect to server: %s\n", + strerror(errno)); return (1); } diff --git a/screen.c b/screen.c index 76aa91c6..2b0e9fba 100644 --- a/screen.c +++ b/screen.c @@ -110,12 +110,8 @@ screen_set_cursor_colour(struct screen *s, const char *colour_string) void screen_set_title(struct screen *s, const char *title) { - char tmp[BUFSIZ]; - - strlcpy(tmp, title, sizeof tmp); - free(s->title); - s->title = xstrdup(tmp); + s->title = xstrdup(title); } /* Resize screen. */ diff --git a/tmux.c b/tmux.c index 74d827a5..c8f9e059 100644 --- a/tmux.c +++ b/tmux.c @@ -361,7 +361,11 @@ main(int argc, char **argv) } } free(label); - strlcpy(socket_path, path, sizeof socket_path); + + if (strlcpy(socket_path, path, sizeof socket_path) >= sizeof socket_path) { + fprintf(stderr, "socket path too long: %s\n", path); + exit(1); + } free(path); /* Set process title. */ From 1a0d3cd5d3bfcf15be80b5c9739b039fc7e0f575 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 9 Jan 2014 14:20:55 +0000 Subject: [PATCH 11/26] Allow attach-session -t to accept a window and pane to select them on attach. Based on a diff from J Raynor. --- cmd-attach-session.c | 26 ++++++++++++++++++++++++-- cmd.c | 2 -- tmux.h | 2 ++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/cmd-attach-session.c b/cmd-attach-session.c index c71e6f1f..6fb83d20 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -47,6 +47,9 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, { struct session *s; struct client *c; + struct winlink *wl = NULL; + struct window *w = NULL; + struct window_pane *wp = NULL; const char *update; char *cause; u_int i; @@ -59,12 +62,31 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, return (CMD_RETURN_ERROR); } - if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) - return (CMD_RETURN_ERROR); + if (tflag == NULL) { + if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) + return (CMD_RETURN_ERROR); + } else if (tflag[strcspn(tflag, ":.")] != '\0') { + if ((wl = cmd_find_pane(cmdq, tflag, &s, &wp)) == NULL) + return (CMD_RETURN_ERROR); + } else { + if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) + return (CMD_RETURN_ERROR); + w = cmd_lookup_windowid(tflag); + if (w == NULL && (wp = cmd_lookup_paneid(tflag)) != NULL) + w = wp->window; + if (w != NULL) + wl = winlink_find_by_window(&s->windows, w); + } if (cmdq->client == NULL) return (CMD_RETURN_NORMAL); + if (wl != NULL) { + if (wp != NULL) + window_set_active_pane(wp->window, wp); + session_set_current(s, wl); + } + if (cmdq->client->session != NULL) { if (dflag) { /* diff --git a/cmd.c b/cmd.c index 2edda633..fe55109b 100644 --- a/cmd.c +++ b/cmd.c @@ -126,9 +126,7 @@ struct session *cmd_lookup_session(const char *, int *); struct session *cmd_lookup_session_id(const char *); 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 winlink *cmd_lookup_winlink_windowid(struct session *, const char *); -struct window *cmd_lookup_windowid(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 *); diff --git a/tmux.h b/tmux.h index 81c99f9b..0a4f8fb5 100644 --- a/tmux.h +++ b/tmux.h @@ -1739,6 +1739,8 @@ int cmd_find_index(struct cmd_q *, const char *, struct winlink *cmd_find_pane(struct cmd_q *, const char *, struct session **, struct window_pane **); char *cmd_template_replace(const char *, const char *, int); +struct window *cmd_lookup_windowid(const char *); +struct window_pane *cmd_lookup_paneid(const char *); extern const struct cmd_entry *cmd_table[]; extern const struct cmd_entry cmd_attach_session_entry; extern const struct cmd_entry cmd_bind_key_entry; From c2cac69a22f70cb690ccc97425623f8405013dcf Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 9 Jan 2014 14:28:14 +0000 Subject: [PATCH 12/26] Similar to attach-session, make switch-client -t accept a window and pane. From Johannes Jakobsson. --- cmd-switch-client.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/cmd-switch-client.c b/cmd-switch-client.c index 9db35365..d0544013 100644 --- a/cmd-switch-client.c +++ b/cmd-switch-client.c @@ -59,9 +59,13 @@ cmd_switch_client_key_binding(struct cmd *self, int key) enum cmd_retval cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq) { - struct args *args = self->args; - struct client *c; - struct session *s; + struct args *args = self->args; + struct client *c; + struct session *s; + struct winlink *wl = NULL; + struct window *w = NULL; + struct window_pane *wp = NULL; + const char *tflag; if ((c = cmd_find_client(cmdq, args_get(args, 'c'), 0)) == NULL) return (CMD_RETURN_ERROR); @@ -76,7 +80,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq) } } - s = NULL; + tflag = args_get(args, 't'); if (args_has(args, 'n')) { if ((s = session_next_session(c->session)) == NULL) { cmdq_error(cmdq, "can't find next session"); @@ -94,10 +98,33 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_q *cmdq) cmdq_error(cmdq, "can't find last session"); return (CMD_RETURN_ERROR); } - } else - s = cmd_find_session(cmdq, args_get(args, 't'), 0); - if (s == NULL) - return (CMD_RETURN_ERROR); + } else { + if (tflag == NULL) { + if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) + return (CMD_RETURN_ERROR); + } else if (tflag[strcspn(tflag, ":.")] != '\0') { + if ((wl = cmd_find_pane(cmdq, tflag, &s, &wp)) == NULL) + return (CMD_RETURN_ERROR); + } else { + if ((s = cmd_find_session(cmdq, tflag, 1)) == NULL) + return (CMD_RETURN_ERROR); + w = cmd_lookup_windowid(tflag); + if (w == NULL && + (wp = cmd_lookup_paneid(tflag)) != NULL) + w = wp->window; + if (w != NULL) + wl = winlink_find_by_window(&s->windows, w); + } + + if (cmdq->client == NULL) + return (CMD_RETURN_NORMAL); + + if (wl != NULL) { + if (wp != NULL) + window_set_active_pane(wp->window, wp); + session_set_current(s, wl); + } + } if (c->session != NULL) c->last_session = c->session; From b185449d073b376eb305ff2a68d87fd82ed56377 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 9 Jan 2014 21:20:45 +0000 Subject: [PATCH 13/26] Fix a memory/fd leak reported by Tiago Cunha. --- client.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client.c b/client.c index 1458963c..4cf73fb9 100644 --- a/client.c +++ b/client.c @@ -118,10 +118,15 @@ retry: close(fd); xasprintf(&lockfile, "%s.lock", path); - if ((lockfd = client_get_lock(lockfile)) == -1) + if ((lockfd = client_get_lock(lockfile)) == -1) { + free(lockfile); goto retry; - if (unlink(path) != 0 && errno != ENOENT) + } + if (unlink(path) != 0 && errno != ENOENT) { + free(lockfile); + close(lockfd); return (-1); + } fd = server_start(lockfd, lockfile); free(lockfile); close(lockfd); From 3368b602a868eb6570c4ee92f45c2e0ee78631cb Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 15 Jan 2014 11:44:18 +0000 Subject: [PATCH 14/26] Couple of fixes from cppcheck via Tiago Cunha. --- arguments.c | 3 +-- grid.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/arguments.c b/arguments.c index 4a3f4579..5ff7ed2c 100644 --- a/arguments.c +++ b/arguments.c @@ -78,7 +78,6 @@ struct args * args_parse(const char *template, int argc, char **argv) { struct args *args; - char *ptr; int opt; args = xcalloc(1, sizeof *args); @@ -89,7 +88,7 @@ args_parse(const char *template, int argc, char **argv) while ((opt = getopt(argc, argv, template)) != -1) { if (opt < 0) continue; - if (opt == '?' || (ptr = strchr(template, opt)) == NULL) { + if (opt == '?' || strchr(template, opt) == NULL) { args_free(args); return (NULL); } diff --git a/grid.c b/grid.c index d9b3c716..852423b5 100644 --- a/grid.c +++ b/grid.c @@ -124,7 +124,7 @@ grid_compare(struct grid *ga, struct grid *gb) struct grid_cell *gca, *gcb; u_int xx, yy; - if (ga->sx != gb->sx || ga->sy != ga->sy) + if (ga->sx != gb->sx || ga->sy != gb->sy) return (1); for (yy = 0; yy < ga->sy; yy++) { From 938768ed3de3e38cb96344b8ec7b794b5e828acf Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 15 Jan 2014 11:46:28 +0000 Subject: [PATCH 15/26] Do not attempt to read .tmux.conf if we can't figure out a home directory, from Tiago Cunha. --- tmux.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tmux.c b/tmux.c index c8f9e059..d4848396 100644 --- a/tmux.c +++ b/tmux.c @@ -202,8 +202,9 @@ int main(int argc, char **argv) { struct passwd *pw; - char *s, *path, *label, *home, **var, tmp[MAXPATHLEN]; + char *s, *path, *label, **var, tmp[MAXPATHLEN]; char in[256]; + const char *home; long long pid; int opt, flags, quiet, keys, session; @@ -325,11 +326,15 @@ main(int argc, char **argv) pw = getpwuid(getuid()); if (pw != NULL) home = pw->pw_dir; + else + home = NULL; } - xasprintf(&cfg_file, "%s/.tmux.conf", home); - if (access(cfg_file, R_OK) != 0 && errno == ENOENT) { - free(cfg_file); - cfg_file = NULL; + if (home != NULL) { + xasprintf(&cfg_file, "%s/.tmux.conf", home); + if (access(cfg_file, R_OK) != 0 && errno == ENOENT) { + free(cfg_file); + cfg_file = NULL; + } } } From df680d725751e0fe9eca4403c732ec1332d91d97 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 22 Jan 2014 13:57:49 +0000 Subject: [PATCH 16/26] Only exit copy mode at the bottom if no selection in progress, from Benoit Pierre. --- window-copy.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/window-copy.c b/window-copy.c index dd4f23fa..ddd5bf41 100644 --- a/window-copy.c +++ b/window-copy.c @@ -853,8 +853,12 @@ window_copy_mouse( } else if (m->wheel == MOUSE_WHEEL_DOWN) { for (i = 0; i < 5; i++) window_copy_cursor_down(wp, 1); - if (data->oy == 0) - goto reset_mode; + /* + * We reached the bottom, leave copy mode, + * but only if no selection is in progress. + */ + if (data->oy == 0 && !s->sel.flag) + goto reset_mode; } return; } From 9ee93b3ea30cfa8e67a62b3c6cf522a9e677ca84 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 22 Jan 2014 14:00:08 +0000 Subject: [PATCH 17/26] Do not permit periods in session names (colons are already banned). From J Raynor. --- session.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/session.c b/session.c index 4f6ebed6..11ae2d35 100644 --- a/session.c +++ b/session.c @@ -175,11 +175,11 @@ session_destroy(struct session *s) RB_INSERT(sessions, &dead_sessions, s); } -/* Check a session name is valid: not empty and no colons. */ +/* Check a session name is valid: not empty and no colons or periods. */ int session_check_name(const char *name) { - return (*name != '\0' && strchr(name, ':') == NULL); + return (*name != '\0' && name[strcspn(name, ":.")] == '\0'); } /* Update session active time. */ From d23561f38172d1fd3766bf55390ba750a5bd1b64 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 22 Jan 2014 14:43:42 +0000 Subject: [PATCH 18/26] Merge server-info into show-messages and remove some not useful output. --- Makefile | 1 - cmd-server-info.c | 173 -------------------------------------------- cmd-show-messages.c | 112 +++++++++++++++++++++++++++- tmux.1 | 14 +++- 4 files changed, 120 insertions(+), 180 deletions(-) delete mode 100644 cmd-server-info.c diff --git a/Makefile b/Makefile index 9fa55d9b..96972944 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,6 @@ SRCS= arguments.c \ cmd-select-pane.c \ cmd-select-window.c \ cmd-send-keys.c \ - cmd-server-info.c \ cmd-set-buffer.c \ cmd-set-environment.c \ cmd-set-option.c \ diff --git a/cmd-server-info.c b/cmd-server-info.c deleted file mode 100644 index 6cbabe2b..00000000 --- a/cmd-server-info.c +++ /dev/null @@ -1,173 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2008 Nicholas Marriott - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include - -#include -#include -#include -#include -#include - -#include "tmux.h" - -/* - * Show various information about server. - */ - -enum cmd_retval cmd_server_info_exec(struct cmd *, struct cmd_q *); - -const struct cmd_entry cmd_server_info_entry = { - "server-info", "info", - "", 0, 0, - "", - 0, - NULL, - cmd_server_info_exec -}; - -enum cmd_retval -cmd_server_info_exec(unused struct cmd *self, struct cmd_q *cmdq) -{ - struct tty_term *term; - struct client *c; - struct session *s; - struct winlink *wl; - struct window *w; - struct window_pane *wp; - struct tty_code *code; - const struct tty_term_code_entry *ent; - struct utsname un; - struct job *job; - struct grid *gd; - struct grid_line *gl; - u_int i, j, k, lines; - size_t size; - char out[80]; - char *tim; - time_t t; - - tim = ctime(&start_time); - *strchr(tim, '\n') = '\0'; - cmdq_print(cmdq, "pid %ld, started %s", (long) getpid(), tim); - cmdq_print(cmdq, "socket path %s, debug level %d", socket_path, - debug_level); - if (uname(&un) >= 0) { - cmdq_print(cmdq, "system is %s %s %s %s", - un.sysname, un.release, un.version, un.machine); - } - if (cfg_file != NULL) - cmdq_print(cmdq, "configuration file is %s", cfg_file); - else - cmdq_print(cmdq, "configuration file not specified"); - cmdq_print(cmdq, "protocol version is %d", PROTOCOL_VERSION); - cmdq_print(cmdq, "%s", ""); - - cmdq_print(cmdq, "Clients:"); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) - continue; - - cmdq_print(cmdq,"%2d: %s (%d, %d): %s [%ux%u %s bs=%hho " - "class=%u] [flags=0x%x/0x%x, references=%u]", i, - c->tty.path, c->ibuf.fd, c->tty.fd, c->session->name, - c->tty.sx, c->tty.sy, c->tty.termname, - c->tty.tio.c_cc[VERASE], c->tty.class, - c->flags, c->tty.flags, c->references); - } - cmdq_print(cmdq, "%s", ""); - - cmdq_print(cmdq, "Sessions: [%zu]", sizeof (struct grid_cell)); - RB_FOREACH(s, sessions, &sessions) { - t = s->creation_time.tv_sec; - tim = ctime(&t); - *strchr(tim, '\n') = '\0'; - - cmdq_print(cmdq, "%2u: %s: %u windows (created %s) [%ux%u] " - "[flags=0x%x]", s->id, s->name, - winlink_count(&s->windows), tim, s->sx, s->sy, s->flags); - RB_FOREACH(wl, winlinks, &s->windows) { - w = wl->window; - cmdq_print(cmdq, "%4u: %s [%ux%u] [flags=0x%x, " - "references=%u, last layout=%d]", wl->idx, w->name, - w->sx, w->sy, w->flags, w->references, - w->lastlayout); - j = 0; - TAILQ_FOREACH(wp, &w->panes, entry) { - lines = size = 0; - gd = wp->base.grid; - for (k = 0; k < gd->hsize + gd->sy; k++) { - gl = &gd->linedata[k]; - if (gl->celldata == NULL) - continue; - lines++; - size += gl->cellsize * - sizeof *gl->celldata; - } - cmdq_print(cmdq, - "%6u: %s %lu %d %u/%u, %zu bytes", j, - wp->tty, (u_long) wp->pid, wp->fd, lines, - gd->hsize + gd->sy, size); - j++; - } - } - } - cmdq_print(cmdq, "%s", ""); - - cmdq_print(cmdq, "Terminals:"); - LIST_FOREACH(term, &tty_terms, entry) { - cmdq_print(cmdq, "%s [references=%u, flags=0x%x]:", - term->name, term->references, term->flags); - for (i = 0; i < NTTYCODE; i++) { - ent = &tty_term_codes[i]; - code = &term->codes[ent->code]; - switch (code->type) { - case TTYCODE_NONE: - cmdq_print(cmdq, "%2u: %s: [missing]", - ent->code, ent->name); - break; - case TTYCODE_STRING: - strnvis(out, code->value.string, sizeof out, - VIS_OCTAL|VIS_TAB|VIS_NL); - cmdq_print(cmdq, "%2u: %s: (string) %s", - ent->code, ent->name, out); - break; - case TTYCODE_NUMBER: - cmdq_print(cmdq, "%2u: %s: (number) %d", - ent->code, ent->name, code->value.number); - break; - case TTYCODE_FLAG: - cmdq_print(cmdq, "%2u: %s: (flag) %s", - ent->code, ent->name, - code->value.flag ? "true" : "false"); - break; - } - } - } - cmdq_print(cmdq, "%s", ""); - - cmdq_print(cmdq, "Jobs:"); - LIST_FOREACH(job, &all_jobs, lentry) { - cmdq_print(cmdq, "%s [fd=%d, pid=%d, status=%d]", - job->cmd, job->fd, job->pid, job->status); - } - - return (CMD_RETURN_NORMAL); -} diff --git a/cmd-show-messages.c b/cmd-show-messages.c index f43607aa..a3938e0a 100644 --- a/cmd-show-messages.c +++ b/cmd-show-messages.c @@ -20,6 +20,8 @@ #include #include +#include +#include #include "tmux.h" @@ -31,13 +33,98 @@ enum cmd_retval cmd_show_messages_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_show_messages_entry = { "show-messages", "showmsgs", - "t:", 0, 0, - CMD_TARGET_CLIENT_USAGE, + "IJTt:", 0, 0, + "[-IJT] " CMD_TARGET_CLIENT_USAGE, 0, NULL, cmd_show_messages_exec }; +const struct cmd_entry cmd_server_info_entry = { + "server-info", "info", + "", 0, 0, + "", + 0, + NULL, + cmd_show_messages_exec +}; + +void cmd_show_messages_server (struct cmd_q *); +void cmd_show_messages_terminals (struct cmd_q *); +void cmd_show_messages_jobs (struct cmd_q *); + +void +cmd_show_messages_server (struct cmd_q *cmdq) +{ + char *tim; + + tim = ctime(&start_time); + *strchr(tim, '\n') = '\0'; + + cmdq_print(cmdq, "started %s", tim); + cmdq_print(cmdq, "socket path %s", socket_path); + cmdq_print(cmdq, "debug level %d", debug_level); + cmdq_print(cmdq, "protocol version %d", PROTOCOL_VERSION); +} + +void +cmd_show_messages_terminals (struct cmd_q *cmdq) +{ + struct tty_term *term; + const struct tty_term_code_entry *ent; + struct tty_code *code; + u_int i, n; + char out[80]; + + n = 0; + LIST_FOREACH(term, &tty_terms, entry) { + cmdq_print(cmdq, + "Terminal %u: %s [references=%u, flags=0x%x]:", + n, term->name, term->references, term->flags); + n++; + for (i = 0; i < NTTYCODE; i++) { + ent = &tty_term_codes[i]; + code = &term->codes[ent->code]; + switch (code->type) { + case TTYCODE_NONE: + cmdq_print(cmdq, "%4u: %s: [missing]", + ent->code, ent->name); + break; + case TTYCODE_STRING: + strnvis(out, code->value.string, sizeof out, + VIS_OCTAL|VIS_TAB|VIS_NL); + cmdq_print(cmdq, "%4u: %s: (string) %s", + ent->code, ent->name, out); + break; + case TTYCODE_NUMBER: + cmdq_print(cmdq, "%4u: %s: (number) %d", + ent->code, ent->name, code->value.number); + break; + case TTYCODE_FLAG: + cmdq_print(cmdq, "%4u: %s: (flag) %s", + ent->code, ent->name, + code->value.flag ? "true" : "false"); + break; + } + } + } +} + +void +cmd_show_messages_jobs (struct cmd_q *cmdq) +{ + struct job *job; + u_int n; + + n = 0; + LIST_FOREACH(job, &all_jobs, lentry) { + cmdq_print(cmdq, + "Job %u: %s [fd=%d, pid=%d, status=%d]", + n, job->cmd, job->fd, job->pid, job->status); + n++; + } +} + enum cmd_retval cmd_show_messages_exec(struct cmd *self, struct cmd_q *cmdq) { @@ -46,6 +133,27 @@ cmd_show_messages_exec(struct cmd *self, struct cmd_q *cmdq) struct message_entry *msg; char *tim; u_int i; + int done; + + done = 0; + if (args_has (args, 'I') || self->entry == &cmd_server_info_entry) { + cmd_show_messages_server (cmdq); + done = 1; + } + if (args_has (args, 'T') || self->entry == &cmd_server_info_entry) { + if (done) + cmdq_print (cmdq, "%s", ""); + cmd_show_messages_terminals (cmdq); + done = 1; + } + if (args_has (args, 'J') || self->entry == &cmd_server_info_entry) { + if (done) + cmdq_print (cmdq, "%s", ""); + cmd_show_messages_jobs (cmdq); + done = 1; + } + if (done) + return (CMD_RETURN_NORMAL); if ((c = cmd_find_client(cmdq, args_get(args, 't'), 0)) == NULL) return (CMD_RETURN_ERROR); diff --git a/tmux.1 b/tmux.1 index a2404b4f..e44a44a6 100644 --- a/tmux.1 +++ b/tmux.1 @@ -770,15 +770,24 @@ is specified, only update the client's status bar. Rename the session to .Ar new-name . .It Xo Ic show-messages +.Op Fl IJT .Op Fl t Ar target-client .Xc .D1 (alias: Ic showmsgs ) +Show client messages or server information. Any messages displayed on the status line are saved in a per-client message log, up to a maximum of the limit set by the .Ar message-limit session option for the session attached to that client. -This command displays the log for +With +.Fl t , +display the log for .Ar target-client . +.Fl I, +.Fl J +and +.Fl T +show debugging information about the running server, jobs and terminals. .It Ic source-file Ar path .D1 (alias: Ic source ) Execute commands from @@ -3566,9 +3575,6 @@ specified by .Fl t or the current pane if omitted). If the command doesn't return success, the exit status is also displayed. -.It Ic server-info -.D1 (alias: Ic info ) -Show server information and terminal details. .It Xo Ic wait-for .Op Fl L | S | U .Ar channel From 7d3d9963839e92e56cfd484918c16ef58c0be687 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 22 Jan 2014 22:32:15 +0000 Subject: [PATCH 19/26] Support paste key in copy mode input (for search etc). Also clamp length to screen width. --- window-copy.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/window-copy.c b/window-copy.c index ddd5bf41..48cd4b33 100644 --- a/window-copy.c +++ b/window-copy.c @@ -750,8 +750,10 @@ window_copy_key_input(struct window_pane *wp, int key) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; - size_t inputlen; + size_t inputlen, n; int np; + struct paste_buffer *pb; + u_char ch; switch (mode_key_lookup(&data->mdata, key, NULL)) { case MODEKEYEDIT_CANCEL: @@ -765,6 +767,20 @@ window_copy_key_input(struct window_pane *wp, int key) case MODEKEYEDIT_DELETELINE: *data->inputstr = '\0'; break; + case MODEKEYEDIT_PASTE: + if ((pb = paste_get_top(&global_buffers)) == NULL) + break; + for (n = 0; n < pb->size; n++) { + ch = (u_char) pb->data[n]; + if (ch < 32 || ch == 127) + break; + } + inputlen = strlen(data->inputstr); + + data->inputstr = xrealloc(data->inputstr, 1, inputlen + n + 1); + memcpy(data->inputstr + inputlen, pb->data, n); + data->inputstr[inputlen + n] = '\0'; + break; case MODEKEYEDIT_ENTER: np = data->numprefix; if (np <= 0) @@ -1154,8 +1170,8 @@ window_copy_write_line( struct screen *s = &data->screen; struct options *oo = &wp->window->options; struct grid_cell gc; - char hdr[32]; - size_t last, xoff = 0, size = 0; + char hdr[512]; + size_t last, xoff = 0, size = 0, limit; window_mode_attrs(&gc, oo); @@ -1168,11 +1184,14 @@ window_copy_write_line( screen_write_cursormove(ctx, screen_size_x(s) - size, 0); screen_write_puts(ctx, &gc, "%s", hdr); } else if (py == last && data->inputtype != WINDOW_COPY_OFF) { + limit = sizeof hdr; + if (limit > screen_size_x(s)) + limit = screen_size_x(s); if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) { - xoff = size = xsnprintf(hdr, sizeof hdr, + xoff = size = xsnprintf(hdr, limit, "Repeat: %u", data->numprefix); } else { - xoff = size = xsnprintf(hdr, sizeof hdr, + xoff = size = xsnprintf(hdr, limit, "%s: %s", data->inputprompt, data->inputstr); } screen_write_cursormove(ctx, 0, last); From dda70d4ef1ce155906c123c6880352c4979e4b57 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 27 Jan 2014 23:57:35 +0000 Subject: [PATCH 20/26] Merge start-server into kill-server. --- Makefile | 1 - cmd-kill-server.c | 14 ++++++++++++-- cmd-start-server.c | 42 ------------------------------------------ 3 files changed, 12 insertions(+), 45 deletions(-) delete mode 100644 cmd-start-server.c diff --git a/Makefile b/Makefile index 96972944..a0736bdf 100644 --- a/Makefile +++ b/Makefile @@ -68,7 +68,6 @@ SRCS= arguments.c \ cmd-show-options.c \ cmd-source-file.c \ cmd-split-window.c \ - cmd-start-server.c \ cmd-string.c \ cmd-suspend-client.c \ cmd-swap-pane.c \ diff --git a/cmd-kill-server.c b/cmd-kill-server.c index ef4a3946..6f0b7494 100644 --- a/cmd-kill-server.c +++ b/cmd-kill-server.c @@ -38,10 +38,20 @@ const struct cmd_entry cmd_kill_server_entry = { cmd_kill_server_exec }; +const struct cmd_entry cmd_start_server_entry = { + "start-server", "start", + "", 0, 0, + "", + CMD_STARTSERVER, + NULL, + cmd_kill_server_exec +}; + enum cmd_retval -cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_q *cmdq) +cmd_kill_server_exec(struct cmd *self, unused struct cmd_q *cmdq) { - kill(getpid(), SIGTERM); + if (self->entry == &cmd_kill_server_entry) + kill(getpid(), SIGTERM); return (CMD_RETURN_NORMAL); } diff --git a/cmd-start-server.c b/cmd-start-server.c deleted file mode 100644 index d98f9506..00000000 --- a/cmd-start-server.c +++ /dev/null @@ -1,42 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2007 Nicholas Marriott - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include "tmux.h" - -/* - * Start the server and do nothing else. - */ - -enum cmd_retval cmd_start_server_exec(struct cmd *, struct cmd_q *); - -const struct cmd_entry cmd_start_server_entry = { - "start-server", "start", - "", 0, 0, - "", - CMD_STARTSERVER, - NULL, - cmd_start_server_exec -}; - -enum cmd_retval -cmd_start_server_exec(unused struct cmd *self, unused struct cmd_q *cmdq) -{ - return (CMD_RETURN_NORMAL); -} From c930fd5ff696f5a60e93ed503f0ff57e0bbf6e4d Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 28 Jan 2014 22:19:17 +0000 Subject: [PATCH 21/26] Remember the last active pane in the top-bottom or left-right cell so that it can be restored when moving back to that cell with selectp -L/-R/etc. From Suraj N Kurapati. --- tmux.h | 2 ++ window.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/tmux.h b/tmux.h index 0a4f8fb5..b28f10a0 100644 --- a/tmux.h +++ b/tmux.h @@ -1028,6 +1028,8 @@ struct layout_cell { u_int yoff; struct window_pane *wp; + struct window_pane *lastwp; + struct layout_cells cells; TAILQ_ENTRY(layout_cell) entry; diff --git a/window.c b/window.c index 83e14db6..dcb2a5f1 100644 --- a/window.c +++ b/window.c @@ -61,6 +61,10 @@ struct window_pane_tree all_window_panes; u_int next_window_pane_id; u_int next_window_id; +struct window_pane *window_pane_active_set(struct window_pane *, + struct window_pane *); +void window_pane_active_lost(struct window_pane *, struct window_pane *); + 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 *); @@ -386,6 +390,59 @@ window_resize(struct window *w, u_int sx, u_int sy) w->sy = sy; } +/* + * Restore previously active pane when changing from wp to nextwp. The intended + * pane is in nextwp and it returns the previously focused pane. + */ +struct window_pane * +window_pane_active_set(struct window_pane *wp, struct window_pane *nextwp) +{ + struct layout_cell *lc; + struct window_pane *lastwp; + + /* Target pane's parent must not be an ancestor of source pane. */ + for (lc = wp->layout_cell->parent; lc != NULL; lc = lc->parent) { + if (lc == nextwp->layout_cell->parent) + return (nextwp); + } + + /* + * Previously active pane, if any, must not be the same as the source + * pane. + */ + if (nextwp->layout_cell->parent != NULL) { + lastwp = nextwp->layout_cell->parent->lastwp; + if (lastwp != wp && window_pane_visible(lastwp)) + return (lastwp); + } + return (nextwp); +} + +/* Remember previously active pane when changing from wp to nextwp. */ +void +window_pane_active_lost(struct window_pane *wp, struct window_pane *nextwp) +{ + struct layout_cell *lc, *lc2; + + /* Save the target pane in its parent. */ + nextwp->layout_cell->parent->lastwp = nextwp; + + /* + * Save the source pane in all of its parents up to, but not including, + * the common ancestor of itself and the target panes. + */ + if (wp == NULL) + return; + for (lc = wp->layout_cell->parent; lc != NULL; lc = lc->parent) { + lc2 = nextwp->layout_cell->parent; + for (; lc2 != NULL; lc2 = lc2->parent) { + if (lc == lc2) + return; + } + lc->lastwp = wp; + } +} + void window_set_active_pane(struct window *w, struct window_pane *wp) { @@ -393,6 +450,7 @@ window_set_active_pane(struct window *w, struct window_pane *wp) return; w->last = w->active; w->active = wp; + window_pane_active_lost(w->last, wp); while (!window_pane_visible(w->active)) { w->active = TAILQ_PREV(w->active, window_panes, entry); if (w->active == NULL) @@ -707,6 +765,16 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) void window_pane_destroy(struct window_pane *wp) { + struct window_pane *wp2; + + /* Forget removed pane in all layout cells that remember it. */ + RB_FOREACH(wp2, window_pane_tree, &all_window_panes) { + if (wp2->layout_cell != NULL && + wp2->layout_cell->parent != NULL && + wp2->layout_cell->parent->lastwp == wp) + wp2->layout_cell->parent->lastwp = NULL; + } + window_pane_reset_mode(wp); if (event_initialized(&wp->changes_timer)) @@ -1130,7 +1198,7 @@ window_pane_find_up(struct window_pane *wp) if (wp2->yoff + wp2->sy + 1 != top) continue; if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx) - return (wp2); + return (window_pane_active_set(wp, wp2)); } return (NULL); } @@ -1156,7 +1224,7 @@ window_pane_find_down(struct window_pane *wp) if (wp2->yoff != bottom) continue; if (left >= wp2->xoff && left <= wp2->xoff + wp2->sx) - return (wp2); + return (window_pane_active_set(wp, wp2)); } return (NULL); } @@ -1185,7 +1253,7 @@ window_pane_find_left(struct window_pane *wp) if (wp2->xoff + wp2->sx + 1 != left) continue; if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy) - return (wp2); + return (window_pane_active_set(wp, wp2)); } return (NULL); } @@ -1214,7 +1282,7 @@ window_pane_find_right(struct window_pane *wp) if (wp2->xoff != right) continue; if (top >= wp2->yoff && top <= wp2->yoff + wp2->sy) - return (wp2); + return (window_pane_active_set(wp, wp2)); } return (NULL); } From 945339b443affdaaca260605e15b5a3b9a3c6e16 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 28 Jan 2014 23:07:09 +0000 Subject: [PATCH 22/26] Allow replacing each of the many sets of separate foo-{fg,bg,attr} options with a single foo-style option. For example: set -g status-fg yellow set -g status-bg red set -g status-attr blink Becomes: set -g status-style fg=yellow,bg=red,blink The -a flag to set can be used to add to rather than replace a style. So: set -g status-bg red Becomes: set -ag status-style bg=red Currently this is fully backwards compatible (all *-{fg,bg,attr} options remain) but the plan is to deprecate them over time. From Tiago Cunha. --- Makefile | 1 + cmd-set-option.c | 28 +++++ grid.c | 1 - options-table.c | 269 +++++++++++++++++++++++++++++----------- options.c | 36 ++++++ screen-redraw.c | 20 +-- screen-write.c | 85 +------------ status.c | 118 +++--------------- style.c | 224 ++++++++++++++++++++++++++++++++++ tmux.1 | 310 ++++++++++++++++++++++++++--------------------- tmux.h | 36 ++++-- tty.c | 3 +- window-choose.c | 4 +- window-copy.c | 4 +- window.c | 10 -- 15 files changed, 710 insertions(+), 439 deletions(-) create mode 100644 style.c diff --git a/Makefile b/Makefile index a0736bdf..e566bb2a 100644 --- a/Makefile +++ b/Makefile @@ -113,6 +113,7 @@ SRCS= arguments.c \ session.c \ signal.c \ status.c \ + style.c \ tmux.c \ tty-acs.c \ tty-keys.c \ diff --git a/cmd-set-option.c b/cmd-set-option.c index 1b25fac0..b661913f 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -60,6 +60,9 @@ struct options_entry *cmd_set_option_flag(struct cmd *, struct cmd_q *, struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_q *, const struct options_table_entry *, struct options *, const char *); +struct options_entry *cmd_set_option_style(struct cmd *, struct cmd_q *, + const struct options_table_entry *, struct options *, + const char *); const struct cmd_entry cmd_set_option_entry = { "set-option", "set", @@ -304,9 +307,11 @@ cmd_set_option_set(struct cmd *self, struct cmd_q *cmdq, break; case OPTIONS_TABLE_COLOUR: o = cmd_set_option_colour(self, cmdq, oe, oo, value); + style_update_new(oo, o->name, oe->style); break; case OPTIONS_TABLE_ATTRIBUTES: o = cmd_set_option_attributes(self, cmdq, oe, oo, value); + style_update_new(oo, o->name, oe->style); break; case OPTIONS_TABLE_FLAG: o = cmd_set_option_flag(self, cmdq, oe, oo, value); @@ -314,6 +319,9 @@ cmd_set_option_set(struct cmd *self, struct cmd_q *cmdq, case OPTIONS_TABLE_CHOICE: o = cmd_set_option_choice(self, cmdq, oe, oo, value); break; + case OPTIONS_TABLE_STYLE: + o = cmd_set_option_style(self, cmdq, oe, oo, value); + break; } if (o == NULL) return (-1); @@ -462,3 +470,23 @@ cmd_set_option_choice(unused struct cmd *self, struct cmd_q *cmdq, return (options_set_number(oo, oe->name, choice)); } + +/* Set a style option. */ +struct options_entry * +cmd_set_option_style(struct cmd *self, struct cmd_q *cmdq, + const struct options_table_entry *oe, struct options *oo, + const char *value) +{ + struct args *args = self->args; + struct options_entry *o; + int append; + + append = args_has(args, 'a'); + if ((o = options_set_style(oo, oe->name, value, append)) == NULL) { + cmdq_error(cmdq, "bad style: %s", value); + return (NULL); + } + + style_update_old(oo, oe->name, &o->style); + return (o); +} diff --git a/grid.c b/grid.c index 852423b5..fb838adf 100644 --- a/grid.c +++ b/grid.c @@ -37,7 +37,6 @@ /* Default grid cell data. */ const struct grid_cell grid_default_cell = { 0, 0, 8, 8, (1 << 4) | 1, " " }; -const struct grid_cell grid_marker_cell = { 0, 0, 8, 8, (1 << 4) | 1, "_" }; #define grid_put_cell(gd, px, py, gc) do { \ memcpy(&gd->linedata[py].celldata[px], \ diff --git a/options-table.c b/options-table.c index 97ca90be..4480b344 100644 --- a/options-table.c +++ b/options-table.c @@ -196,32 +196,43 @@ const struct options_table_entry session_options_table[] = { { .name = "message-attr", .type = OPTIONS_TABLE_ATTRIBUTES, - .default_num = 0 + .default_num = 0, + .style = "message-style" }, { .name = "message-bg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 3 + .default_num = 3, + .style = "message-style" }, { .name = "message-command-attr", .type = OPTIONS_TABLE_ATTRIBUTES, - .default_num = 0 + .default_num = 0, + .style = "message-command-style" }, { .name = "message-command-bg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 0 + .default_num = 0, + .style = "message-command-style" }, { .name = "message-command-fg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 3 + .default_num = 3, + .style = "message-command-style" + }, + + { .name = "message-command-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "bg=black,fg=yellow" }, { .name = "message-fg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 0 + .default_num = 0, + .style = "message-style" }, { .name = "message-limit", @@ -231,6 +242,11 @@ const struct options_table_entry session_options_table[] = { .default_num = 20 }, + { .name = "message-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "bg=yellow,fg=black" + }, + { .name = "mouse-resize-pane", .type = OPTIONS_TABLE_FLAG, .default_num = 0 @@ -253,22 +269,36 @@ const struct options_table_entry session_options_table[] = { { .name = "pane-active-border-bg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + .default_num = 8, + .style = "pane-active-border-style" }, { .name = "pane-active-border-fg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 2 + .default_num = 2, + .style = "pane-active-border-style" + }, + + { .name = "pane-active-border-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "fg=green" }, { .name = "pane-border-bg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + .default_num = 8, + .style = "pane-border-style" }, { .name = "pane-border-fg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + .default_num = 8, + .style = "pane-border-style" + }, + + { .name = "pane-border-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "default" }, { .name = "prefix", @@ -315,17 +345,20 @@ const struct options_table_entry session_options_table[] = { { .name = "status-attr", .type = OPTIONS_TABLE_ATTRIBUTES, - .default_num = 0 + .default_num = 0, + .style = "status-style" }, { .name = "status-bg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 2 + .default_num = 2, + .style = "status-style" }, { .name = "status-fg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 0 + .default_num = 0, + .style = "status-style" }, { .name = "status-interval", @@ -354,17 +387,20 @@ const struct options_table_entry session_options_table[] = { { .name = "status-left-attr", .type = OPTIONS_TABLE_ATTRIBUTES, - .default_num = 0 + .default_num = 0, + .style = "status-left-style" }, { .name = "status-left-bg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + .default_num = 8, + .style = "status-left-style" }, { .name = "status-left-fg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + .default_num = 8, + .style = "status-left-style" }, { .name = "status-left-length", @@ -374,6 +410,11 @@ const struct options_table_entry session_options_table[] = { .default_num = 10 }, + { .name = "status-left-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "default" + }, + { .name = "status-position", .type = OPTIONS_TABLE_CHOICE, .choices = options_table_status_position_list, @@ -387,17 +428,20 @@ const struct options_table_entry session_options_table[] = { { .name = "status-right-attr", .type = OPTIONS_TABLE_ATTRIBUTES, - .default_num = 0 + .default_num = 0, + .style = "status-right-style" }, { .name = "status-right-bg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + .default_num = 8, + .style = "status-right-style" }, { .name = "status-right-fg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + .default_num = 8, + .style = "status-right-style" }, { .name = "status-right-length", @@ -407,6 +451,16 @@ const struct options_table_entry session_options_table[] = { .default_num = 40 }, + { .name = "status-right-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "default" + }, + + { .name = "status-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "bg=green,fg=black" + }, + { .name = "status-utf8", .type = OPTIONS_TABLE_FLAG, .default_num = 0 /* overridden in main() */ @@ -537,17 +591,20 @@ const struct options_table_entry window_options_table[] = { { .name = "mode-attr", .type = OPTIONS_TABLE_ATTRIBUTES, - .default_num = 0 + .default_num = 0, + .style = "mode-style" }, { .name = "mode-bg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 3 + .default_num = 3, + .style = "mode-style" }, { .name = "mode-fg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 0 + .default_num = 0, + .style = "mode-style" }, { .name = "mode-keys", @@ -562,6 +619,11 @@ const struct options_table_entry window_options_table[] = { .default_num = 0 }, + { .name = "mode-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "bg=yellow,fg=black" + }, + { .name = "monitor-activity", .type = OPTIONS_TABLE_FLAG, .default_num = 0 @@ -617,72 +679,101 @@ const struct options_table_entry window_options_table[] = { { .name = "window-status-activity-attr", .type = OPTIONS_TABLE_ATTRIBUTES, - .default_num = GRID_ATTR_REVERSE + .default_num = GRID_ATTR_REVERSE, + .style = "window-status-activity-style" }, { .name = "window-status-activity-bg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + .default_num = 8, + .style = "window-status-activity-style" }, { .name = "window-status-activity-fg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + .default_num = 8, + .style = "window-status-activity-style" }, - { .name = "window-status-bell-attr", - .type = OPTIONS_TABLE_ATTRIBUTES, - .default_num = GRID_ATTR_REVERSE - }, - - { .name = "window-status-bell-bg", - .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 - }, - - { .name = "window-status-bell-fg", - .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 - }, - - { .name = "window-status-content-attr", - .type = OPTIONS_TABLE_ATTRIBUTES, - .default_num = GRID_ATTR_REVERSE - }, - - { .name = "window-status-content-bg", - .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 - }, - - { .name = "window-status-content-fg", - .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + { .name = "window-status-activity-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "reverse" }, { .name = "window-status-attr", .type = OPTIONS_TABLE_ATTRIBUTES, - .default_num = 0 + .default_num = 0, + .style = "window-status-style" + }, + + { .name = "window-status-bell-attr", + .type = OPTIONS_TABLE_ATTRIBUTES, + .default_num = GRID_ATTR_REVERSE, + .style = "window-status-bell-style" + }, + + { .name = "window-status-bell-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8, + .style = "window-status-bell-style" + }, + + { .name = "window-status-bell-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8, + .style = "window-status-bell-style" + }, + + { .name = "window-status-bell-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "reverse" }, { .name = "window-status-bg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + .default_num = 8, + .style = "window-status-style" + }, + + { .name = "window-status-content-attr", + .type = OPTIONS_TABLE_ATTRIBUTES, + .default_num = GRID_ATTR_REVERSE, + .style = "window-status-content-style" + }, + + { .name = "window-status-content-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8, + .style = "window-status-content-style" + }, + + { .name = "window-status-content-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8, + .style = "window-status-content-style" + }, + + { .name = "window-status-content-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "reverse" }, { .name = "window-status-current-attr", .type = OPTIONS_TABLE_ATTRIBUTES, - .default_num = 0 + .default_num = 0, + .style = "window-status-current-style" }, { .name = "window-status-current-bg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + .default_num = 8, + .style = "window-status-current-style" }, { .name = "window-status-current-fg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + .default_num = 8, + .style = "window-status-current-style" }, { .name = "window-status-current-format", @@ -690,24 +781,15 @@ const struct options_table_entry window_options_table[] = { .default_str = "#I:#W#F" }, - { .name = "window-status-last-attr", - .type = OPTIONS_TABLE_ATTRIBUTES, - .default_num = 0 - }, - - { .name = "window-status-last-bg", - .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 - }, - - { .name = "window-status-last-fg", - .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + { .name = "window-status-current-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "default" }, { .name = "window-status-fg", .type = OPTIONS_TABLE_COLOUR, - .default_num = 8 + .default_num = 8, + .style = "window-status-style" }, { .name = "window-status-format", @@ -715,11 +797,39 @@ const struct options_table_entry window_options_table[] = { .default_str = "#I:#W#F" }, + { .name = "window-status-last-attr", + .type = OPTIONS_TABLE_ATTRIBUTES, + .default_num = 0, + .style = "window-status-last-style" + }, + + { .name = "window-status-last-bg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8, + .style = "window-status-last-style" + }, + + { .name = "window-status-last-fg", + .type = OPTIONS_TABLE_COLOUR, + .default_num = 8, + .style = "window-status-last-style" + }, + + { .name = "window-status-last-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "default" + }, + { .name = "window-status-separator", .type = OPTIONS_TABLE_STRING, .default_str = " " }, + { .name = "window-status-style", + .type = OPTIONS_TABLE_STYLE, + .default_str = "default" + }, + { .name = "wrap-search", .type = OPTIONS_TABLE_FLAG, .default_num = 1 @@ -741,10 +851,17 @@ options_table_populate_tree( const struct options_table_entry *oe; for (oe = table; oe->name != NULL; oe++) { - if (oe->default_str != NULL) + switch (oe->type) { + case OPTIONS_TABLE_STRING: options_set_string(oo, oe->name, "%s", oe->default_str); - else + break; + case OPTIONS_TABLE_STYLE: + options_set_style(oo, oe->name, oe->default_str); + break; + default: options_set_number(oo, oe->name, oe->default_num); + break; + } } } @@ -789,6 +906,10 @@ options_table_print_entry(const struct options_table_entry *oe, s = oe->choices[o->num]; xsnprintf(out, sizeof out, "%s", s); break; + case OPTIONS_TABLE_STYLE: + s = style_tostring(&o->style); + xsnprintf(out, sizeof out, "%s", s); + break; } return (out); } diff --git a/options.c b/options.c index 51a6608e..699dd9b0 100644 --- a/options.c +++ b/options.c @@ -109,6 +109,7 @@ options_set_string(struct options *oo, const char *name, const char *fmt, ...) o = xmalloc(sizeof *o); o->name = xstrdup(name); RB_INSERT(options_tree, &oo->tree, o); + memcpy(&o->style, &grid_default_cell, sizeof o->style); } else if (o->type == OPTIONS_STRING) free(o->str); @@ -140,6 +141,7 @@ options_set_number(struct options *oo, const char *name, long long value) o = xmalloc(sizeof *o); o->name = xstrdup(name); RB_INSERT(options_tree, &oo->tree, o); + memcpy(&o->style, &grid_default_cell, sizeof o->style); } else if (o->type == OPTIONS_STRING) free(o->str); @@ -159,3 +161,37 @@ options_get_number(struct options *oo, const char *name) fatalx("option not a number"); return (o->num); } + +struct options_entry * +options_set_style(struct options *oo, const char *name, const char *value, + int append) +{ + struct options_entry *o; + + if ((o = options_find1(oo, name)) == NULL) { + o = xmalloc(sizeof *o); + o->name = xstrdup(name); + RB_INSERT(options_tree, &oo->tree, o); + } else if (o->type == OPTIONS_STRING) + free(o->str); + + if (!append) + memcpy(&o->style, &grid_default_cell, sizeof o->style); + + o->type = OPTIONS_STYLE; + if (style_parse(&grid_default_cell, &o->style, value) == -1) + return (NULL); + return (o); +} + +struct grid_cell * +options_get_style(struct options *oo, const char *name) +{ + struct options_entry *o; + + if ((o = options_find(oo, name)) == NULL) + fatalx("missing option"); + if (o->type != OPTIONS_STYLE) + fatalx("option not a style"); + return (&o->style); +} diff --git a/screen-redraw.c b/screen-redraw.c index 4601c6f3..a67cb952 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -224,7 +224,7 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) struct window_pane *wp; struct grid_cell active_gc, other_gc; u_int i, j, type, top; - int status, spos, fg, bg; + int status, spos; /* Suspended clients should not be updated. */ if (c->flags & CLIENT_SUSPENDED) @@ -251,17 +251,9 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) } /* Set up pane border attributes. */ - memcpy(&other_gc, &grid_marker_cell, sizeof other_gc); - memcpy(&active_gc, &grid_marker_cell, sizeof active_gc); - active_gc.attr = other_gc.attr = GRID_ATTR_CHARSET; - fg = options_get_number(oo, "pane-border-fg"); - colour_set_fg(&other_gc, fg); - bg = options_get_number(oo, "pane-border-bg"); - colour_set_bg(&other_gc, bg); - fg = options_get_number(oo, "pane-active-border-fg"); - colour_set_fg(&active_gc, fg); - bg = options_get_number(oo, "pane-active-border-bg"); - colour_set_bg(&active_gc, bg); + style_apply(&other_gc, oo, "pane-border-style"); + style_apply(&active_gc, oo, "pane-active-border-style"); + active_gc.attr = other_gc.attr = GRID_ATTR_CHARSET; /* nuke existing */ /* Draw background and borders. */ for (j = 0; j < tty->sy - status; j++) { @@ -368,7 +360,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) px -= len * 3; py -= 2; - memcpy(&gc, &grid_marker_cell, sizeof gc); + memcpy(&gc, &grid_default_cell, sizeof gc); if (w->active == wp) colour_set_bg(&gc, active_colour); else @@ -395,7 +387,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp) tty_cursor(tty, xoff + wp->sx - len, yoff); draw_text: - memcpy(&gc, &grid_marker_cell, sizeof gc); + memcpy(&gc, &grid_default_cell, sizeof gc); if (w->active == wp) colour_set_fg(&gc, active_colour); else diff --git a/screen-write.c b/screen-write.c index 7fcfc5ee..3da145e8 100644 --- a/screen-write.c +++ b/screen-write.c @@ -248,7 +248,7 @@ screen_write_cnputs(struct screen_write_ctx *ctx, } *last = '\0'; - screen_write_parsestyle(gc, &lgc, ptr); + style_parse(gc, &lgc, ptr); ptr = last + 1; continue; } @@ -288,89 +288,6 @@ screen_write_cnputs(struct screen_write_ctx *ctx, free(msg); } -/* Parse an embedded style of the form "fg=colour,bg=colour,bright,...". */ -void -screen_write_parsestyle( - struct grid_cell *defgc, struct grid_cell *gc, const char *in) -{ - const char delimiters[] = " ,"; - char tmp[32]; - int val; - size_t end; - u_char fg, bg, attr, flags; - - if (*in == '\0') - return; - if (strchr(delimiters, in[strlen(in) - 1]) != NULL) - return; - - fg = gc->fg; - bg = gc->bg; - attr = gc->attr; - flags = gc->flags; - do { - end = strcspn(in, delimiters); - if (end > (sizeof tmp) - 1) - return; - memcpy(tmp, in, end); - tmp[end] = '\0'; - - if (strcasecmp(tmp, "default") == 0) { - fg = defgc->fg; - bg = defgc->bg; - attr = defgc->attr; - flags &= ~(GRID_FLAG_FG256|GRID_FLAG_BG256); - flags |= - defgc->flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); - } else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) { - if ((val = colour_fromstring(tmp + 3)) == -1) - return; - if (*in == 'f' || *in == 'F') { - if (val != 8) { - if (val & 0x100) { - flags |= GRID_FLAG_FG256; - val &= ~0x100; - } else - flags &= ~GRID_FLAG_FG256; - fg = val; - } else { - fg = defgc->fg; - flags &= ~GRID_FLAG_FG256; - flags |= defgc->flags & GRID_FLAG_FG256; - } - } else if (*in == 'b' || *in == 'B') { - if (val != 8) { - if (val & 0x100) { - flags |= GRID_FLAG_BG256; - val &= ~0x100; - } else - flags &= ~GRID_FLAG_BG256; - bg = val; - } else { - bg = defgc->bg; - flags &= ~GRID_FLAG_BG256; - flags |= defgc->flags & GRID_FLAG_BG256; - } - } else - return; - } else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) { - if ((val = attributes_fromstring(tmp + 2)) == -1) - return; - attr &= ~val; - } else { - if ((val = attributes_fromstring(tmp)) == -1) - return; - attr |= val; - } - - in += end + strspn(in + end, delimiters); - } while (*in != '\0'); - gc->fg = fg; - gc->bg = bg; - gc->attr = attr; - gc->flags = flags; -} - /* Copy from another screen. */ void screen_write_copy(struct screen_write_ctx *ctx, diff --git a/status.c b/status.c index c5572b74..e14c1a81 100644 --- a/status.c +++ b/status.c @@ -80,18 +80,9 @@ status_redraw_get_left(struct client *c, { struct session *s = c->session; char *left; - int fg, bg, attr; size_t leftlen; - fg = options_get_number(&s->options, "status-left-fg"); - if (fg != 8) - colour_set_fg(gc, fg); - bg = options_get_number(&s->options, "status-left-bg"); - if (bg != 8) - colour_set_bg(gc, bg); - attr = options_get_number(&s->options, "status-left-attr"); - if (attr != 0) - gc->attr = attr; + style_apply_update(gc, &s->options, "status-left-style"); left = status_replace(c, NULL, NULL, NULL, options_get_string(&s->options, "status-left"), t, 1); @@ -110,18 +101,9 @@ status_redraw_get_right(struct client *c, { struct session *s = c->session; char *right; - int fg, bg, attr; size_t rightlen; - fg = options_get_number(&s->options, "status-right-fg"); - if (fg != 8) - colour_set_fg(gc, fg); - bg = options_get_number(&s->options, "status-right-bg"); - if (bg != 8) - colour_set_bg(gc, bg); - attr = options_get_number(&s->options, "status-right-attr"); - if (attr != 0) - gc->attr = attr; + style_apply_update(gc, &s->options, "status-right-style"); right = status_replace(c, NULL, NULL, NULL, options_get_string(&s->options, "status-right"), t, 1); @@ -177,10 +159,7 @@ status_redraw(struct client *c) t = c->status_timer.tv_sec; /* Set up default colour. */ - memcpy(&stdgc, &grid_default_cell, sizeof gc); - colour_set_fg(&stdgc, options_get_number(&s->options, "status-fg")); - colour_set_bg(&stdgc, options_get_number(&s->options, "status-bg")); - stdgc.attr |= options_get_number(&s->options, "status-attr"); + style_apply(&stdgc, &s->options, "status-style"); /* Create the target screen. */ memcpy(&old_status, &c->status, sizeof old_status); @@ -646,73 +625,22 @@ status_print( struct session *s = c->session; const char *fmt; char *text; - int fg, bg, attr; - fg = options_get_number(oo, "window-status-fg"); - if (fg != 8) - colour_set_fg(gc, fg); - bg = options_get_number(oo, "window-status-bg"); - if (bg != 8) - colour_set_bg(gc, bg); - attr = options_get_number(oo, "window-status-attr"); - if (attr != 0) - gc->attr = attr; + style_apply_update(gc, oo, "window-status-style"); fmt = options_get_string(oo, "window-status-format"); if (wl == s->curw) { - fg = options_get_number(oo, "window-status-current-fg"); - if (fg != 8) - colour_set_fg(gc, fg); - bg = options_get_number(oo, "window-status-current-bg"); - if (bg != 8) - colour_set_bg(gc, bg); - attr = options_get_number(oo, "window-status-current-attr"); - if (attr != 0) - gc->attr = attr; + style_apply_update(gc, oo, "window-status-current-style"); fmt = options_get_string(oo, "window-status-current-format"); } - if (wl == TAILQ_FIRST(&s->lastw)) { - fg = options_get_number(oo, "window-status-last-fg"); - if (fg != 8) - colour_set_fg(gc, fg); - bg = options_get_number(oo, "window-status-last-bg"); - if (bg != 8) - colour_set_bg(gc, bg); - attr = options_get_number(oo, "window-status-last-attr"); - if (attr != 0) - gc->attr = attr; - } + if (wl == TAILQ_FIRST(&s->lastw)) + style_apply_update(gc, oo, "window-status-last-style"); - if (wl->flags & WINLINK_BELL) { - fg = options_get_number(oo, "window-status-bell-fg"); - if (fg != 8) - colour_set_fg(gc, fg); - bg = options_get_number(oo, "window-status-bell-bg"); - if (bg != 8) - colour_set_bg(gc, bg); - attr = options_get_number(oo, "window-status-bell-attr"); - if (attr != 0) - gc->attr = attr; - } else if (wl->flags & WINLINK_CONTENT) { - fg = options_get_number(oo, "window-status-content-fg"); - if (fg != 8) - colour_set_fg(gc, fg); - bg = options_get_number(oo, "window-status-content-bg"); - if (bg != 8) - colour_set_bg(gc, bg); - attr = options_get_number(oo, "window-status-content-attr"); - if (attr != 0) - gc->attr = attr; - } else if (wl->flags & (WINLINK_ACTIVITY|WINLINK_SILENCE)) { - fg = options_get_number(oo, "window-status-activity-fg"); - if (fg != 8) - colour_set_fg(gc, fg); - bg = options_get_number(oo, "window-status-activity-bg"); - if (bg != 8) - colour_set_bg(gc, bg); - attr = options_get_number(oo, "window-status-activity-attr"); - if (attr != 0) - gc->attr = attr; - } + if (wl->flags & WINLINK_BELL) + style_apply_update(gc, oo, "window-status-bell-style"); + else if (wl->flags & WINLINK_CONTENT) + style_apply_update(gc, oo, "window-status-content-style"); + else if (wl->flags & (WINLINK_ACTIVITY|WINLINK_SILENCE)) + style_apply_update(gc, oo, "window-status-activity-style"); text = status_replace(c, NULL, wl, NULL, fmt, t, 1); return (text); @@ -814,10 +742,7 @@ status_message_redraw(struct client *c) if (len > c->tty.sx) len = c->tty.sx; - memcpy(&gc, &grid_default_cell, sizeof gc); - colour_set_fg(&gc, options_get_number(&s->options, "message-fg")); - colour_set_bg(&gc, options_get_number(&s->options, "message-bg")); - gc.attr |= options_get_number(&s->options, "message-attr"); + style_apply(&gc, &s->options, "message-style"); screen_write_start(&ctx, NULL, &c->status); @@ -935,18 +860,11 @@ status_prompt_redraw(struct client *c) len = c->tty.sx; off = 0; - memcpy(&gc, &grid_default_cell, sizeof gc); - /* Change colours for command mode. */ - if (c->prompt_mdata.mode == 1) { - colour_set_fg(&gc, options_get_number(&s->options, "message-command-fg")); - colour_set_bg(&gc, options_get_number(&s->options, "message-command-bg")); - gc.attr |= options_get_number(&s->options, "message-command-attr"); - } else { - colour_set_fg(&gc, options_get_number(&s->options, "message-fg")); - colour_set_bg(&gc, options_get_number(&s->options, "message-bg")); - gc.attr |= options_get_number(&s->options, "message-attr"); - } + if (c->prompt_mdata.mode == 1) + style_apply(&gc, &s->options, "message-command-style"); + else + style_apply(&gc, &s->options, "message-style"); screen_write_start(&ctx, NULL, &c->status); diff --git a/style.c b/style.c new file mode 100644 index 00000000..97d5576e --- /dev/null +++ b/style.c @@ -0,0 +1,224 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2007 Nicholas Marriott + * Copyright (c) 2014 Tiago Cunha + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "tmux.h" + +/* Parse an embedded style of the form "fg=colour,bg=colour,bright,...". */ +int +style_parse(const struct grid_cell *defgc, struct grid_cell *gc, + const char *in) +{ + const char delimiters[] = " ,"; + char tmp[32]; + int val; + size_t end; + u_char fg, bg, attr, flags; + + if (*in == '\0') + return (0); + if (strchr(delimiters, in[strlen(in) - 1]) != NULL) + return (-1); + + fg = gc->fg; + bg = gc->bg; + attr = gc->attr; + flags = gc->flags; + do { + end = strcspn(in, delimiters); + if (end > (sizeof tmp) - 1) + return (-1); + memcpy(tmp, in, end); + tmp[end] = '\0'; + + if (strcasecmp(tmp, "default") == 0) { + fg = defgc->fg; + bg = defgc->bg; + attr = defgc->attr; + flags &= ~(GRID_FLAG_FG256|GRID_FLAG_BG256); + flags |= + defgc->flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); + } else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) { + if ((val = colour_fromstring(tmp + 3)) == -1) + return (-1); + if (*in == 'f' || *in == 'F') { + if (val != 8) { + if (val & 0x100) { + flags |= GRID_FLAG_FG256; + val &= ~0x100; + } else + flags &= ~GRID_FLAG_FG256; + fg = val; + } else { + fg = defgc->fg; + flags &= ~GRID_FLAG_FG256; + flags |= defgc->flags & GRID_FLAG_FG256; + } + } else if (*in == 'b' || *in == 'B') { + if (val != 8) { + if (val & 0x100) { + flags |= GRID_FLAG_BG256; + val &= ~0x100; + } else + flags &= ~GRID_FLAG_BG256; + bg = val; + } else { + bg = defgc->bg; + flags &= ~GRID_FLAG_BG256; + flags |= defgc->flags & GRID_FLAG_BG256; + } + } else + return (-1); + } else if (strcasecmp(tmp, "none") == 0) + attr = 0; + else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) { + if ((val = attributes_fromstring(tmp + 2)) == -1) + return (-1); + attr &= ~val; + } else { + if ((val = attributes_fromstring(tmp)) == -1) + return (-1); + attr |= val; + } + + in += end + strspn(in + end, delimiters); + } while (*in != '\0'); + gc->fg = fg; + gc->bg = bg; + gc->attr = attr; + gc->flags = flags; + + return (0); +} + +/* Convert style to a string. */ +const char * +style_tostring(struct grid_cell *gc) +{ + int c, off = 0, comma = 0; + static char s[256]; + + *s = '\0'; + + if (gc->fg != 8) { + if (gc->flags & GRID_FLAG_FG256) + c = gc->fg | 0x100; + else + c = gc->fg; + off += xsnprintf(s, sizeof s, "fg=%s", colour_tostring(c)); + comma = 1; + } + + if (gc->bg != 8) { + if (gc->flags & GRID_FLAG_BG256) + c = gc->bg | 0x100; + else + c = gc->bg; + off += xsnprintf(s + off, sizeof s - off, "%sbg=%s", + comma ? "," : "", colour_tostring(c)); + comma = 1; + } + + if (gc->attr != 0 && gc->attr != GRID_ATTR_CHARSET) { + xsnprintf(s + off, sizeof s - off, "%s%s", + comma ? "," : "", attributes_tostring(gc->attr)); + } + + if (*s == '\0') + return ("default"); + return (s); +} + +/* Synchronize new -style option with the old one. */ +void +style_update_new(struct options *oo, const char *name, const char *newname) +{ + int value; + struct grid_cell *gc; + + /* It's a colour or attribute, but with no -style equivalent. */ + if (newname == NULL) + return; + + gc = options_get_style(oo, newname); + value = options_get_number(oo, name); + + if (strstr(name, "-bg") != NULL) + colour_set_bg(gc, value); + else if (strstr(name, "-fg") != NULL) + colour_set_fg(gc, value); + else if (strstr(name, "-attr") != NULL) + gc->attr = value; +} + +/* Synchronize all the old options with the new -style one. */ +void +style_update_old(struct options *oo, const char *name, struct grid_cell *gc) +{ + char newname[128]; + int c, size; + + size = strrchr(name, '-') - name; + + if (gc->flags & GRID_FLAG_BG256) + c = gc->bg | 0x100; + else + c = gc->bg; + xsnprintf(newname, sizeof newname, "%.*s-bg", size, name); + options_set_number(oo, newname, c); + + if (gc->flags & GRID_FLAG_FG256) + c = gc->fg | 0x100; + else + c = gc->fg; + xsnprintf(newname, sizeof newname, "%.*s-fg", size, name); + options_set_number(oo, newname, c); + + xsnprintf(newname, sizeof newname, "%.*s-attr", size, name); + options_set_number(oo, newname, gc->attr); +} + +/* Apply a style. */ +void +style_apply(struct grid_cell *gc, struct options *oo, const char *name) +{ + struct grid_cell *gcp; + + memcpy(gc, &grid_default_cell, sizeof *gc); + gcp = options_get_style(oo, name); + colour_set_fg(gc, gcp->fg); + colour_set_bg(gc, gcp->bg); + gc->attr |= gcp->attr; +} + +/* Apply a style, updating if default. */ +void +style_apply_update(struct grid_cell *gc, struct options *oo, const char *name) +{ + struct grid_cell *gcp; + + gcp = options_get_style(oo, name); + if (gcp->fg != 8) + colour_set_fg(gc, gcp->fg); + if (gcp->bg != 8) + colour_set_bg(gc, gcp->bg); + if (gcp->attr != 0) + gc->attr |= gcp->attr; +} diff --git a/tmux.1 b/tmux.1 index e44a44a6..e0b27b6d 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2060,11 +2060,6 @@ otherwise a session option. If .Fl g is specified, the global session or window option is set. -With -.Fl a , -and if the option expects a string, -.Ar value -is appended to the existing setting. The .Fl u flag unsets an option, so a session inherits the option from the global @@ -2081,6 +2076,32 @@ flag suppresses the informational message (as if the .Ic quiet server option was set). .Pp +With +.Fl a , +and if the option expects a string or a style, +.Ar value +is appended to the existing setting. +For example: +.Bd -literal -offset indent +set -g status-left "foo" +set -ag status-left "bar" +.Ed +.Pp +Will result in +.Ql foobar . +And: +.Bd -literal -offset indent +set -g status-style "bg=red" +set -ag status-style "fg=blue" +.Ed +.Pp +Will result in a red background +.Em and +blue foreground. +Without +.Fl a , +the result would be the default background and a blue foreground. +.Pp Available window options are listed under .Ic set-window-option . .Pp @@ -2272,26 +2293,18 @@ the entire server will lock after .Em all sessions would have locked. This has no effect as a session option; it must be set as a global option. -.It Ic message-attr Ar attributes -Set status line message attributes, where -.Ar attributes -is either -.Ic none -or a comma-delimited list of one or more of: -.Ic bright -(or -.Ic bold ) , -.Ic dim , -.Ic underscore , -.Ic blink , -.Ic reverse , -.Ic hidden , -or -.Ic italics . -.It Ic message-bg Ar colour -Set status line message background colour, where -.Ar colour -is one of: +.It Ic message-command-style Ar style +Set status line message command style, where +.Ar style +is a comma-separated list of characteristics to be specified. +.Pp +These may be +.Ql bg=colour +to set the background colour, +.Ql fg=colour +to set the foreground colour, and a list of attributes as specified below. +.Pp +The colour is one of: .Ic black , .Ic red , .Ic green , @@ -2312,18 +2325,46 @@ from the 256-colour set, or a hexadecimal RGB string such as .Ql #ffffff , which chooses the closest match from the default 256-colour set. -.It Ic message-command-attr Ar attributes -Set status line message attributes when in command mode. -.It Ic message-command-bg Ar colour -Set status line message background colour when in command mode. -.It Ic message-command-fg Ar colour -Set status line message foreground colour when in command mode. -.It Ic message-fg Ar colour -Set status line message foreground colour. +.Pp +The attributes is either +.Ic none +or a comma-delimited list of one or more of: +.Ic bright +(or +.Ic bold ) , +.Ic dim , +.Ic underscore , +.Ic blink , +.Ic reverse , +.Ic hidden , +or +.Ic italics , +to turn an attribute on, or an attribute prefixed with +.Ql no +to turn one off. +.Pp +Examples are: +.Bd -literal -offset indent +fg=yellow,bold,underscore,blink +bg=black,fg=default,noreverse +.Ed +.Pp +With the +.Fl a +flag to the +.Ic set-option +command the new style is added otherwise the existing style is replaced. .It Ic message-limit Ar number Set the number of error or information messages to save in the message log for each client. The default is 20. +.It Ic message-style Ar style +Set status line message style. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. .It Xo Ic mouse-resize-pane .Op Ic on | off .Xc @@ -2347,12 +2388,22 @@ window. .Op Ic on | off .Xc If enabled, request mouse input as UTF-8 on UTF-8 terminals. -.It Ic pane-active-border-bg Ar colour -.It Ic pane-active-border-fg Ar colour -Set the pane border colour for the currently active pane. -.It Ic pane-border-bg Ar colour -.It Ic pane-border-fg Ar colour -Set the pane border colour for panes aside from the active pane. +.It Ic pane-active-border-style Ar style +Set the pane border style for the currently active pane. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. +Attributes are ignored. +.It Ic pane-border-style Ar style +Set the pane border style for paneas aside from the active pane. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. +Attributes are ignored. .It Ic prefix Ar key Set the key accepted as a prefix key. .It Ic prefix2 Ar key @@ -2418,12 +2469,6 @@ option. .Op Ic on | off .Xc Show or hide the status line. -.It Ic status-attr Ar attributes -Set status line attributes. -.It Ic status-bg Ar colour -Set status line background colour. -.It Ic status-fg Ar colour -Set status line foreground colour. .It Ic status-interval Ar interval Update the status bar every .Ar interval @@ -2481,19 +2526,10 @@ section). For details on how the names and titles can be set see the .Sx "NAMES AND TITLES" section. +For a list of allowed attributes see the +.Ic message-command-style +option. .Pp -#[attributes] allows a comma-separated list of attributes to be specified, -these may be -.Ql fg=colour -to set the foreground colour, -.Ql bg=colour -to set the background colour, the name of one of the attributes (listed under -the -.Ic message-attr -option) to turn an attribute on, or an attribute prefixed with -.Ql no -to turn one off, for example -.Ic nobright . Examples are: .Bd -literal -offset indent #(sysctl vm.loadavg) @@ -2509,17 +2545,18 @@ By default, UTF-8 in is not interpreted, to enable UTF-8, use the .Ic status-utf8 option. -.It Ic status-left-attr Ar attributes -Set the attribute of the left part of the status line. -.It Ic status-left-bg Ar colour -Set the background colour of the left part of the status line. -.It Ic status-left-fg Ar colour -Set the foreground colour of the left part of the status line. .It Ic status-left-length Ar length Set the maximum .Ar length of the left component of the status bar. The default is 10. +.It Ic status-left-style Ar style +Set the style of the left part of the status line. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. .It Xo Ic status-position .Op Ic top | bottom .Xc @@ -2538,17 +2575,25 @@ will be passed to character pairs are replaced, and UTF-8 is dependent on the .Ic status-utf8 option. -.It Ic status-right-attr Ar attributes -Set the attribute of the right part of the status line. -.It Ic status-right-bg Ar colour -Set the background colour of the right part of the status line. -.It Ic status-right-fg Ar colour -Set the foreground colour of the right part of the status line. .It Ic status-right-length Ar length Set the maximum .Ar length of the right component of the status bar. The default is 40. +.It Ic status-right-style Ar style +Set the style of the right part of the status line. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. +.It Ic status-style Ar style +Set status line style. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. .It Xo Ic status-utf8 .Op Ic on | off .Xc @@ -2775,15 +2820,6 @@ or .Ic main-vertical layouts. .Pp -.It Ic mode-attr Ar attributes -Set window modes attributes. -.Pp -.It Ic mode-bg Ar colour -Set window modes background colour. -.Pp -.It Ic mode-fg Ar colour -Set window modes foreground colour. -.Pp .It Xo Ic mode-keys .Op Ic vi | emacs .Xc @@ -2809,6 +2845,14 @@ If set to the mouse behaves as set to on, but cannot be used to enter copy mode. .Pp +.It Ic mode-style Ar style +Set window modes style. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. +.Pp .It Xo Ic monitor-activity .Op Ic on | off .Xc @@ -2879,64 +2923,42 @@ Instructs .Nm to expect UTF-8 sequences to appear in this window. .Pp -.It Ic window-status-bell-attr Ar attributes -Set status line attributes for windows which have a bell alert. +.It Ic window-status-activity-style Ar style +Set status line style for windows with an activity alert. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. .Pp -.It Ic window-status-bell-bg Ar colour -Set status line background colour for windows with a bell alert. +.It Ic window-status-bell-style Ar style +Set status line style for windows with a bell alert. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. .Pp -.It Ic window-status-bell-fg Ar colour -Set status line foreground colour for windows with a bell alert. -.Pp -.It Ic window-status-content-attr Ar attributes -Set status line attributes for windows which have a content alert. -.Pp -.It Ic window-status-content-bg Ar colour -Set status line background colour for windows with a content alert. -.Pp -.It Ic window-status-content-fg Ar colour -Set status line foreground colour for windows with a content alert. -.Pp -.It Ic window-status-activity-attr Ar attributes -Set status line attributes for windows which have an activity (or silence) alert. -.Pp -.It Ic window-status-activity-bg Ar colour -Set status line background colour for windows with an activity alert. -.Pp -.It Ic window-status-activity-fg Ar colour -Set status line foreground colour for windows with an activity alert. -.Pp -.It Ic window-status-attr Ar attributes -Set status line attributes for a single window. -.Pp -.It Ic window-status-bg Ar colour -Set status line background colour for a single window. -.Pp -.It Ic window-status-current-attr Ar attributes -Set status line attributes for the currently active window. -.Pp -.It Ic window-status-current-bg Ar colour -Set status line background colour for the currently active window. -.Pp -.It Ic window-status-current-fg Ar colour -Set status line foreground colour for the currently active window. +.It Ic window-status-content-style Ar style +Set status line style for windows with a content alert. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. .Pp .It Ic window-status-current-format Ar string Like .Ar window-status-format , but is the format used when the window is the current window. .Pp -.It Ic window-status-last-attr Ar attributes -Set status line attributes for the last active window. -.Pp -.It Ic window-status-last-bg Ar colour -Set status line background colour for the last active window. -.Pp -.It Ic window-status-last-fg Ar colour -Set status line foreground colour for the last active window. -.Pp -.It Ic window-status-fg Ar colour -Set status line foreground colour for a single window. +.It Ic window-status-current-style Ar style +Set status line style for the currently active window. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. .Pp .It Ic window-status-format Ar string Set the format in which the window is displayed in the status line window list. @@ -2946,10 +2968,26 @@ option for details of special character sequences available. The default is .Ql #I:#W#F . .Pp +.It Ic window-status-last-style Ar style +Set status line style for the last active window. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. +.Pp .It Ic window-status-separator Ar string Sets the separator drawn between windows in the status line. The default is a single space character. .Pp +.It Ic window-status-style Ar style +Set status line style for a single window. +For how to specify +.Ar style , +see the +.Ic message-command-style +option. +.Pp .It Xo Ic xterm-keys .Op Ic on | off .Xc @@ -3288,16 +3326,10 @@ content) is present. .Pp The colour and attributes of the status line may be configured, the entire status line using the -.Ic status-attr , -.Ic status-fg -and -.Ic status-bg -session options and individual windows using the -.Ic window-status-attr , -.Ic window-status-fg -and -.Ic window-status-bg -window options. +.Ic status-style +session option and individual windows using the +.Ic window-status-style +window option. .Pp The status line is automatically refreshed at interval if it has changed, the interval may be controlled with the @@ -3798,7 +3830,7 @@ bind-key C-a send-prefix Turning the status line off, or changing its colour: .Bd -literal -offset indent set-option -g status off -set-option -g status-bg blue +set-option -g status-style bg=blue .Ed .Pp Setting other options, such as the default command, diff --git a/tmux.h b/tmux.h index b28f10a0..b8fd445c 100644 --- a/tmux.h +++ b/tmux.h @@ -726,11 +726,12 @@ struct options_entry { enum { OPTIONS_STRING, OPTIONS_NUMBER, - OPTIONS_DATA, + OPTIONS_STYLE } type; - char *str; - long long num; + char *str; + long long num; + struct grid_cell style; RB_ENTRY(options_entry) entry; }; @@ -1453,7 +1454,8 @@ enum options_table_type { OPTIONS_TABLE_COLOUR, OPTIONS_TABLE_ATTRIBUTES, OPTIONS_TABLE_FLAG, - OPTIONS_TABLE_CHOICE + OPTIONS_TABLE_CHOICE, + OPTIONS_TABLE_STYLE }; struct options_table_entry { @@ -1466,6 +1468,8 @@ struct options_table_entry { const char *default_str; long long default_num; + + const char *style; }; /* Tree of format entries. */ @@ -1577,12 +1581,15 @@ void options_free(struct options *); struct options_entry *options_find1(struct options *, const char *); struct options_entry *options_find(struct options *, const char *); void options_remove(struct options *, const char *); -struct options_entry *printflike3 options_set_string( - struct options *, const char *, const char *, ...); +struct options_entry *printflike3 options_set_string(struct options *, + const char *, const char *, ...); char *options_get_string(struct options *, const char *); -struct options_entry *options_set_number( - struct options *, const char *, long long); +struct options_entry *options_set_number(struct options *, const char *, + long long); long long options_get_number(struct options *, const char *); +struct options_entry *options_set_style(struct options *, const char *, + const char *, int); +struct grid_cell *options_get_style(struct options *, const char *); /* options-table.c */ extern const struct options_table_entry server_options_table[]; @@ -2042,8 +2049,6 @@ void printflike5 screen_write_nputs(struct screen_write_ctx *, ssize_t, struct grid_cell *, int, const char *, ...); void screen_write_vnputs(struct screen_write_ctx *, ssize_t, struct grid_cell *, int, const char *, va_list); -void screen_write_parsestyle( - struct grid_cell *, struct grid_cell *, const char *); void screen_write_putc( struct screen_write_ctx *, struct grid_cell *, u_char); void screen_write_copy(struct screen_write_ctx *, @@ -2173,7 +2178,6 @@ struct window_pane *window_pane_find_right(struct window_pane *); void window_set_name(struct window *, const char *); void window_remove_ref(struct window *); void winlink_clear_flags(struct winlink *); -void window_mode_attrs(struct grid_cell *, struct options *); /* layout.c */ u_int layout_count_cells(struct layout_cell *); @@ -2345,4 +2349,14 @@ int xvasprintf(char **, const char *, va_list); int printflike3 xsnprintf(char *, size_t, const char *, ...); int xvsnprintf(char *, size_t, const char *, va_list); +/* style.c */ +int style_parse(const struct grid_cell *, + struct grid_cell *, const char *); +const char *style_tostring(struct grid_cell *); +void style_update_new(struct options *, const char *, const char *); +void style_update_old(struct options *, const char *, + struct grid_cell *); +void style_apply(struct grid_cell *, struct options *, const char *); +void style_apply_update(struct grid_cell *, struct options *, const char *); + #endif /* TMUX_H */ diff --git a/tty.c b/tty.c index 53b415ff..f5a85992 100644 --- a/tty.c +++ b/tty.c @@ -1354,8 +1354,7 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) tty_putcode(tty, TTYC_BOLD); if (changed & GRID_ATTR_DIM) tty_putcode(tty, TTYC_DIM); - if (changed & GRID_ATTR_ITALICS) - { + if (changed & GRID_ATTR_ITALICS) { if (tty_term_has(tty->term, TTYC_SITM)) tty_putcode(tty, TTYC_SITM); else diff --git a/window-choose.c b/window-choose.c index 77add5e4..0cf7f66b 100644 --- a/window-choose.c +++ b/window-choose.c @@ -736,7 +736,7 @@ window_choose_write_line( utf8flag = options_get_number(&wp->window->options, "utf8"); memcpy(&gc, &grid_default_cell, sizeof gc); if (data->selected == data->top + py) - window_mode_attrs(&gc, oo); + style_apply(&gc, oo, "mode-style"); screen_write_cursormove(ctx, 0, py); if (data->top + py < ARRAY_LENGTH(&data->list)) { @@ -763,7 +763,7 @@ window_choose_write_line( screen_write_putc(ctx, &gc, ' '); if (data->input_type != WINDOW_CHOOSE_NORMAL) { - window_mode_attrs(&gc, oo); + style_apply(&gc, oo, "mode-style"); xoff = xsnprintf(hdr, sizeof hdr, "%s: %s", data->input_prompt, data->input_str); diff --git a/window-copy.c b/window-copy.c index 48cd4b33..df4ca55a 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1173,7 +1173,7 @@ window_copy_write_line( char hdr[512]; size_t last, xoff = 0, size = 0, limit; - window_mode_attrs(&gc, oo); + style_apply(&gc, oo, "mode-style"); last = screen_size_y(s) - 1; if (py == 0) { @@ -1290,7 +1290,7 @@ window_copy_update_selection(struct window_pane *wp, int may_redraw) return (0); /* Set colours. */ - window_mode_attrs(&gc, oo); + style_apply(&gc, oo, "mode-style"); /* Find top of screen. */ ty = screen_hsize(data->backing) - data->oy; diff --git a/window.c b/window.c index dcb2a5f1..1e11cace 100644 --- a/window.c +++ b/window.c @@ -1315,13 +1315,3 @@ winlink_clear_flags(struct winlink *wl) } } } - -/* Set the grid_cell with fg/bg/attr information when window is in a mode. */ -void -window_mode_attrs(struct grid_cell *gc, struct options *oo) -{ - memcpy(gc, &grid_default_cell, sizeof *gc); - colour_set_fg(gc, options_get_number(oo, "mode-fg")); - colour_set_bg(gc, options_get_number(oo, "mode-bg")); - gc->attr |= options_get_number(oo, "mode-attr"); -} From 62e0ed5d7eac5470e4ad2fbde5034d3fa72343c0 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 28 Jan 2014 23:11:44 +0000 Subject: [PATCH 23/26] Fix missing argument, stupid last minute changes... --- options-table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options-table.c b/options-table.c index 4480b344..ec1d3680 100644 --- a/options-table.c +++ b/options-table.c @@ -856,7 +856,7 @@ options_table_populate_tree( options_set_string(oo, oe->name, "%s", oe->default_str); break; case OPTIONS_TABLE_STYLE: - options_set_style(oo, oe->name, oe->default_str); + options_set_style(oo, oe->name, oe->default_str, 0); break; default: options_set_number(oo, oe->name, oe->default_num); From 1935eb5c1ea697762a142ca5353ade82d9a372a1 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 31 Jan 2014 11:17:20 +0000 Subject: [PATCH 24/26] Add \033[18t window operations from J Raynor. --- input.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/input.c b/input.c index e27250ed..58064ddd 100644 --- a/input.c +++ b/input.c @@ -74,6 +74,7 @@ void input_csi_dispatch_rm(struct input_ctx *); 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(struct input_ctx *); int input_dcs_dispatch(struct input_ctx *); int input_utf8_open(struct input_ctx *); @@ -154,6 +155,7 @@ enum input_csi_type { INPUT_CSI_SM_PRIVATE, INPUT_CSI_TBC, INPUT_CSI_VPA, + INPUT_CSI_WINOPS, }; /* Control (CSI) command table. */ @@ -188,6 +190,7 @@ const struct input_table_entry input_csi_table[] = { { 'q', " ", INPUT_CSI_DECSCUSR }, { 'r', "", INPUT_CSI_DECSTBM }, { 's', "", INPUT_CSI_SCP }, + { 't', "", INPUT_CSI_WINOPS }, { 'u', "", INPUT_CSI_RCP }, }; @@ -1077,7 +1080,7 @@ input_csi_dispatch(struct input_ctx *ictx) struct screen_write_ctx *sctx = &ictx->ctx; struct screen *s = sctx->s; struct input_table_entry *entry; - int n, m; + int n, m; if (ictx->flags & INPUT_DISCARD) return (0); @@ -1117,6 +1120,9 @@ input_csi_dispatch(struct input_ctx *ictx) m = input_get(ictx, 1, 1, 1); screen_write_cursormove(sctx, m - 1, n - 1); break; + case INPUT_CSI_WINOPS: + input_csi_dispatch_winops(ictx); + break; case INPUT_CSI_CUU: screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1)); break; @@ -1430,6 +1436,55 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx) } } +/* Handle CSI window operations. */ +void +input_csi_dispatch_winops(struct input_ctx *ictx) +{ + struct window_pane *wp = ictx->wp; + int n, m; + + m = 0; + while ((n = input_get(ictx, m, 0, -1)) != -1) { + switch (n) { + case 1: + case 2: + case 5: + case 6: + case 7: + case 11: + case 13: + case 14: + case 19: + case 20: + case 21: + case 24: + break; + case 3: + case 4: + case 8: + m++; + if (input_get(ictx, m, 0, -1) == -1) + return; + /* FALLTHROUGH */ + case 9: + case 10: + case 22: + case 23: + m++; + if (input_get(ictx, m, 0, -1) == -1) + return; + break; + case 18: + input_reply(ictx, "\033[8;%u;%u", wp->sy, wp->sx); + break; + default: + log_debug("%s: unknown '%c'", __func__, ictx->ch); + break; + } + m++; + } +} + /* Handle CSI SGR. */ void input_csi_dispatch_sgr(struct input_ctx *ictx) From 72d1be5ddd0dbc87f99d5430bb4ee4a295ea193b Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 31 Jan 2014 11:20:28 +0000 Subject: [PATCH 25/26] Fix partial matches with xterm-keys on, from m0viefreak dot cm at googlemail dot com. --- xterm-keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xterm-keys.c b/xterm-keys.c index 75eb6751..9b5a0a21 100644 --- a/xterm-keys.c +++ b/xterm-keys.c @@ -133,7 +133,7 @@ xterm_keys_match(const char *template, const char *buf, size_t len) do { if (*template != '_' && buf[pos] != *template) return (-1); - } while (pos++ != len && *++template != '\0'); + } while (*++template != '\0' && ++pos != len); if (*template != '\0') /* partial */ return (1); From 9f02feb9d089b1a4639afb52ab0e8212eeb55a7c Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 31 Jan 2014 14:19:24 +0000 Subject: [PATCH 26/26] Break up and simplify screen_redraw_screen. --- screen-redraw.c | 153 +++++++++++++++++++++++++----------------------- server-client.c | 6 +- tmux.h | 2 +- 3 files changed, 84 insertions(+), 77 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index a67cb952..3a082cbf 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -29,6 +29,9 @@ int screen_redraw_check_cell(struct client *, u_int, u_int, int screen_redraw_check_active(u_int, u_int, int, struct window *, struct window_pane *); +void screen_redraw_draw_borders(struct client *, int, u_int); +void screen_redraw_draw_panes(struct client *, u_int); +void screen_redraw_draw_status(struct client *, u_int); void screen_redraw_draw_number(struct client *, struct window_pane *); #define CELL_INSIDE 0 @@ -216,15 +219,13 @@ screen_redraw_check_active(u_int px, u_int py, int type, struct window *w, /* Redraw entire screen. */ void -screen_redraw_screen(struct client *c, int status_only, int borders_only) +screen_redraw_screen(struct client *c, int draw_panes, int draw_status, + int draw_borders) { - struct window *w = c->session->curw->window; - struct options *oo = &c->session->options; - struct tty *tty = &c->tty; - struct window_pane *wp; - struct grid_cell active_gc, other_gc; - u_int i, j, type, top; - int status, spos; + struct options *oo = &c->session->options; + struct tty *tty = &c->tty; + u_int top; + int status, spos; /* Suspended clients should not be updated. */ if (c->flags & CLIENT_SUSPENDED) @@ -239,72 +240,15 @@ screen_redraw_screen(struct client *c, int status_only, int borders_only) top = 0; if (status && spos == 0) top = 1; + if (!status) + draw_status = 0; - /* If only drawing status and it is present, don't need the rest. */ - if (status_only && status) { - if (top) - tty_draw_line(tty, &c->status, 0, 0, 0); - else - tty_draw_line(tty, &c->status, 0, 0, tty->sy - 1); - tty_reset(tty); - return; - } - - /* Set up pane border attributes. */ - style_apply(&other_gc, oo, "pane-border-style"); - style_apply(&active_gc, oo, "pane-active-border-style"); - active_gc.attr = other_gc.attr = GRID_ATTR_CHARSET; /* nuke existing */ - - /* Draw background and borders. */ - for (j = 0; j < tty->sy - status; j++) { - if (status_only) { - if (spos == 1 && j != tty->sy - 1) - continue; - else if (spos == 0 && j != 0) - break; - } - for (i = 0; i < tty->sx; i++) { - type = screen_redraw_check_cell(c, i, j, &wp); - if (type == CELL_INSIDE) - continue; - if (screen_redraw_check_active(i, j, type, w, wp)) - tty_attributes(tty, &active_gc); - else - tty_attributes(tty, &other_gc); - tty_cursor(tty, i, top + j); - tty_putc(tty, CELL_BORDERS[type]); - } - } - - /* If only drawing borders, that's it. */ - if (borders_only) - return; - - /* Draw the panes, if necessary. */ - TAILQ_FOREACH(wp, &w->panes, entry) { - if (!window_pane_visible(wp)) - continue; - for (i = 0; i < wp->sy; i++) { - if (status_only) { - if (spos == 1 && wp->yoff + i != tty->sy - 1) - continue; - else if (spos == 0 && wp->yoff + i != 0) - break; - } - tty_draw_line( - tty, wp->screen, i, wp->xoff, top + wp->yoff); - } - if (c->flags & CLIENT_IDENTIFY) - screen_redraw_draw_number(c, wp); - } - - /* Draw the status line. */ - if (status) { - if (top) - tty_draw_line(tty, &c->status, 0, 0, 0); - else - tty_draw_line(tty, &c->status, 0, 0, tty->sy - 1); - } + if (draw_borders) + screen_redraw_draw_borders(c, status, top); + if (draw_panes) + screen_redraw_draw_panes(c, top); + if (draw_status) + screen_redraw_draw_status(c, top); tty_reset(tty); } @@ -326,6 +270,69 @@ screen_redraw_pane(struct client *c, struct window_pane *wp) tty_reset(&c->tty); } +/* Draw the borders. */ +void +screen_redraw_draw_borders(struct client *c, int status, u_int top) +{ + struct window *w = c->session->curw->window; + struct options *oo = &c->session->options; + struct tty *tty = &c->tty; + struct window_pane *wp; + struct grid_cell active_gc, other_gc; + u_int i, j, type; + + style_apply(&other_gc, oo, "pane-border-style"); + style_apply(&active_gc, oo, "pane-active-border-style"); + active_gc.attr = other_gc.attr = GRID_ATTR_CHARSET; + + for (j = 0; j < tty->sy - status; j++) { + for (i = 0; i < tty->sx; i++) { + type = screen_redraw_check_cell(c, i, j, &wp); + if (type == CELL_INSIDE) + continue; + if (screen_redraw_check_active(i, j, type, w, wp)) + tty_attributes(tty, &active_gc); + else + tty_attributes(tty, &other_gc); + tty_cursor(tty, i, top + j); + tty_putc(tty, CELL_BORDERS[type]); + } + } +} + +/* Draw the panes. */ +void +screen_redraw_draw_panes(struct client *c, u_int top) +{ + struct window *w = c->session->curw->window; + struct tty *tty = &c->tty; + struct window_pane *wp; + struct screen *s; + u_int i; + + TAILQ_FOREACH(wp, &w->panes, entry) { + if (!window_pane_visible(wp)) + continue; + s = wp->screen; + for (i = 0; i < wp->sy; i++) + tty_draw_line(tty, s, i, wp->xoff, top + wp->yoff); + if (c->flags & CLIENT_IDENTIFY) + screen_redraw_draw_number(c, wp); + } +} + +/* Draw the status line. */ +void +screen_redraw_draw_status(struct client *c, u_int top) +{ + struct tty *tty = &c->tty; + + if (top) + tty_draw_line(tty, &c->status, 0, 0, 0); + else + tty_draw_line(tty, &c->status, 0, 0, tty->sy - 1); +} + /* Draw number on a pane. */ void screen_redraw_draw_number(struct client *c, struct window_pane *wp) diff --git a/server-client.c b/server-client.c index c6257edb..5a6cb7d9 100644 --- a/server-client.c +++ b/server-client.c @@ -743,7 +743,7 @@ server_client_check_redraw(struct client *c) } if (c->flags & CLIENT_REDRAW) { - screen_redraw_screen(c, 0, 0); + screen_redraw_screen(c, 1, 1, 1); c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS); } else if (c->flags & CLIENT_REDRAWWINDOW) { TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) @@ -757,10 +757,10 @@ server_client_check_redraw(struct client *c) } if (c->flags & CLIENT_BORDERS) - screen_redraw_screen(c, 0, 1); + screen_redraw_screen(c, 0, 0, 1); if (c->flags & CLIENT_STATUS) - screen_redraw_screen(c, 1, 0); + screen_redraw_screen(c, 0, 1, 0); c->tty.flags |= flags; diff --git a/tmux.h b/tmux.h index b8fd445c..c6919622 100644 --- a/tmux.h +++ b/tmux.h @@ -2084,7 +2084,7 @@ void screen_write_setselection(struct screen_write_ctx *, u_char *, u_int); void screen_write_rawstring(struct screen_write_ctx *, u_char *, u_int); /* screen-redraw.c */ -void screen_redraw_screen(struct client *, int, int); +void screen_redraw_screen(struct client *, int, int, int); void screen_redraw_pane(struct client *, struct window_pane *); /* screen.c */